Andreas, thank you for your answer! What is the well? I believe the streaming work so we unarchive the this on the fly then write to url to avoid unnecessary actions with copy * * On Thu, Mar 22, 2012 at 4:10 PM, Andreas Grosam <agro...@onlinehome.de>wrote:
> > On Mar 21, 2012, at 4:59 PM, Ariel Feinerman wrote: > > > Hi, > > > I wish to insert an asynchronous NSURLConnection into non-concurrent > > NSOperation > > the reason is to allow necessarily unarchive actions on the streaming > date > > > Is this for iOS or Mac OS? > > This for iOS > > > > The date is very large their amount is 400 Mb so the asynchronous is > > necessarily > > one cannot be in memory at once > > > > - (void) connection: (NSURLConnection *) connection didReceiveData: > > (NSData*) data { > > // Append the new data to receivedData. > > [_receivedData appendData: data]; > > if ([_receivedData length] >= MAX_CHUNK) { > > // unarchive > > // write to file > > // [receivedData setLength: 0]; > > } > > > > } > > > > Is there a correct way to do ? > > Yes. > > And your described approach works fine - if your connection delegates run > on a secondary thread. Not sure, if you are actually required to use > NSOperation, but basically, when you start your connection on a secondary > thread (in order to keep the main thread responsive), it should work fine. > (See the code below, how one can accomplish to start a connection on a > secondary thread.) > > Though, your approach is not optimal and it also **requires** that you can > actually process (unarchive) **partial** data. > > > If you cannot process partial data, you have to search for a more > elaborated solution to this problem: > > There are several approaches, from simple to more complex. And, there are > approaches which look promising but won't work! > > What you need to use in any case is an **asynchronous** (NSURL)connection. > Don't use a synchronously scheduled NSURLConnection with that amount of > data! > > 1) The simplest one that works is to immediately write the received data > to a temporary file (appending partial data to a file works fine). Then > when finished downloading, process the temporary file, possibly leveraging > mmap, NSStream, GCD or NSOperation. For this approach, you don't need > anything special in the NSURLConnection. Starting it from the main thread > is sufficient. Writing to the temp file is usually fast enough to keep the > main thread responsive. > When you are processing the data, you can schedule the task on a secondary > thread. > > This approach is simple to implement, but is suboptimal performance wise - > especially on devices with more than one CPU. > > > 2) An approach that combines high performance with low memory foot-print > is one that is a bit more elaborated. This would also require to schedule > the connection on a secondary thread. (example on request) > > > 3) A few approaches that WONT work and will likely eventually crash are > the following: > > 3.a) > - (void) connection:(NSURLConnection*)connection didReceiveData:(NSData*) > data > { > dispatch_async(queue, ^{processData:data;}]; > } > where processData: is supposed to be able to handle partial data. > This will likely crash due to memory running out: If downloading is fast, > and processing is slow, GCD queues a lot of buffers - until memory runs out. > > 3.b) > - (void) connection:(NSURLConnection*)connection didReceiveData:(NSData*) > data > { > [_receivedData appendData: data]; > } > And when finished, processing _receivedData. > This will crash due to memory running out. > > > > > > Regards > > Andreas > > > > ====================================================== > > You can start a connection in a secondary thread, as follows: > > Anywhere, for instance a ViewController handling the "Start" Button: > > // start the NSURLConnection in a secondary thread: > [NSThread detachNewThreadSelector:@selector > (startConnectionInSecondaryThread) > toTarget:self withObject:nil]; > > > And -startConnectionInSecondaryThread is implemented: > > static NSString* kDownloadConnectionRunLoopMode = > @"MyViewControllerDownloadConnectionRunMode"; > > Won't this thrash the work? - (void) startConnectionInSecondaryThread > { > NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; > [self startConnection]; > runLoopDone_ = NO; > // Enable the run loop: > // first, add a dummy source in order to prevent the Run loop from > exiting > // immediately when the connection closes : > [[NSRunLoop currentRunLoop] addPort:[NSMachPort port] > forMode:kDownloadConnectionRunLoopMode]; > do { > BOOL processedSource = [[NSRunLoop currentRunLoop] > runMode:kDownloadConnectionRunLoopMode beforeDate:[NSDate distantFuture]]; > } while (!runLoopDone_); > > [pool release]; > } > > > And finally, -startConnection, which is shown in more detail, to show some > things you need to care about: > > - (void) startConnection > { > // Note: startConnection can be performed on secondary threads, thus we > need > // to schedule UIKit methods onto the main thread. > > NSString* urlString = @"http://exmample.com"; > NSURL* url = [NSURL URLWithString:urlString]; > > // Possibly configure/clear URL cache > > NSTimeInterval request_timeout = 60.0; > NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:url > cachePolicy:0 timeoutInterval:request_timeout]; > > [request setValue:@"gzip,deflate" forHTTPHeaderField:@ > "Accept-Encoding"]; > NSLog(@"Request header: %@", [request allHTTPHeaderFields]); > > // Create the URL connection and set its delegate: > NSURLConnection* tmp = [[NSURLConnection alloc] initWithRequest:request > delegate:self > startImmediately:NO]; > self.connection = tmp; > [tmp release]; > > if (connection_ == nil) { > dispatch_async(dispatch_get_main_queue(), ^{ > [self > handleError:makeError(@"NSURLConnectionDownloadViewController", 3, > @"Failure to create URL connection.")]; > self.messageLabel.text = @"creating connection failed"; > self.startDownloadButton.enabled = NO; > }); > > return; > } > > NSLog(@"Start downloading %@", urlString); > dispatch_async(dispatch_get_main_queue(), ^{ > self.messageLabel.text = @"start connection request"; > // Start the status bar network activity indicator. We'll turn it > off when > // the connection finishes or experiences an error. > [UIApplication sharedApplication].networkActivityIndicatorVisible = > YES; > self.startDownloadButton.enabled = NO; > self.cancelButton.enabled = YES; > }); > > > // Schedule the connection's delegate methods in the current thread's > run loop: > [connection_ scheduleInRunLoop: [NSRunLoop currentRunLoop] forMode: > kDownloadConnectionRunLoopMode]; > > // Start the download > [self.connection start]; > } > > > ==================================================== > > > _______________________________________________ > > Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) > > Please do not post admin requests or moderator comments to the list. > Contact the moderators at cocoa-dev-admins(at)lists.apple.com > > Help/Unsubscribe/Update your Subscription: > https://lists.apple.com/mailman/options/cocoa-dev/arielfapple%40gmail.com > > This email sent to arielfap...@gmail.com > -- best regards Ariel _______________________________________________ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com