Re: asynchronous nsurlconnection in nsoperation

2012-03-23 Thread Ariel Feinerman
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.dewrote:


 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;;
   

Re: asynchronous nsurlconnection in nsoperation

2012-03-23 Thread Steve Sisak

At 6:59 PM +0300 3/21/12, Ariel Feinerman wrote:

I wish to insert an asynchronous NSURLConnection into non-concurrent
NSOperation the reason is to allow necessarily unarchive actions on 
the streaming date so


Look at (and steal code from) the LinkedImageFetcher sample:

http://developer.apple.com/library/mac/#samplecode/LinkedImageFetcher/

I'm pretty sure if you steal the Core Code directory, and subclass 
QHTTPOperation, that ought to do pretty much what you want.


HTH,

-Steve
___

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


Re: asynchronous nsurlconnection in nsoperation

2012-03-23 Thread Andreas Grosam

On Mar 23, 2012, at 11:25 AM, Steve Sisak wrote:

 At 6:59 PM +0300 3/21/12, Ariel Feinerman wrote:
 I wish to insert an asynchronous NSURLConnection into non-concurrent
 NSOperation the reason is to allow necessarily unarchive actions on the 
 streaming date so
 
 Look at (and steal code from) the LinkedImageFetcher sample:
 
 http://developer.apple.com/library/mac/#samplecode/LinkedImageFetcher/
 
 I'm pretty sure if you steal the Core Code directory, and subclass 
 QHTTPOperation, that ought to do pretty much what you want.
 
 HTH,
 
 -Steve


The LinkedImageFetcher sample is quite a good example to look at when you are 
required to use NSOperation to wrap a download. For a sample, it is quite 
complex though.

So, basically, QHTTPOperation is a good but rather complex example which shows 
how to run a NSURLConnection on a secondary thread, and also how to wrap it 
into a NSOperation which can be canceled etc.

Still, the sample is not a good example to show how to *process* arbitrary data 
*during* the download process. The sample shows two ways to handle data:
-  write the received data into an NSOutputStream, and 
-  store the content into an accumulator - which is a mutable NSData.

The latter disqualifies since the OP's data is about several MBytes large, too 
large for a mobile device. 

And when the NSOutputStream is an ordinary file stream, we gain nothing than 
writing into a file directly, which can be accomplished much easier.

If you subclass the NSOutputStream in order to achieve a fancier processing, 
you will nevertheless run into issues which are completely orthogonal to using 
NSOperation. 

Furthermore, using NSStreams is often unduly cumbersome and often not that easy 
as it sounds. You need a bound stream pair, and there have been various issues 
with this.

Still, any process that handles the data via NSStreams must be able to handle 
such data in **chunks**. If this is not possible, the solution with NSStream 
becomes even more complex - if feasible at all. See also, 
https://devforums.apple.com/message/608213#608213

If the data *can* be processed *partially*, then the simplest approach is just 
doing this in

- (void) connection:(NSURLConnection*)connection didReceiveData:(NSData*) data 
{
   [self processChunk:data];
}

where  processChunk: must perform synchronously - that is, it shall block until 
after that chunk of data has been processed completely and has relinquished 
ownership from data.

If it would perform asynchronously, many NSData buffers may possibly queued - 
and this may consume too much memory.


Andreas

___

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


Re: asynchronous nsurlconnection in nsoperation

2012-03-22 Thread Ariel Feinerman
Is this for iOS or Mac OS?

This for iOS


   // dispatch_async(kBgQueue, ^{ NSData* data = [NSData
dataWithContentsOfURL: myUrl]; // THIS IS WHAT YOU WANT Ariel **
The date is very large their amount is 400 Mb so the asynchronous is
necessarily
one cannot be in memory at once

On Wed, Mar 21, 2012 at 10:36 PM, Sebastian Celis
li...@sebastiancelis.comwrote:

 On Wed, Mar 21, 2012 at 10:59 AM, Ariel Feinerman arielfap...@gmail.com
 wrote:
  I wish to insert an asynchronous NSURLConnection into non-concurrent
  NSOperation

 Hi Ariel,

 MBRequest does this. It is done by forcing the operation's runloop to
 continue running while the network connection is in progress. I would
 recommend looking though the source code. Specifically, take a look at
 MBURLConnectionOperation.

 https://github.com/mobiata/MBRequest

 https://github.com/mobiata/MBRequest/blob/master/Classes/MBURLConnectionOperation.m

 - Sebastian




-- 
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


Re: asynchronous nsurlconnection in nsoperation

2012-03-22 Thread Andreas Grosam

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;

- (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 

asynchronous nsurlconnection in nsoperation

2012-03-21 Thread Ariel Feinerman
Hi,

I wish to insert an asynchronous NSURLConnection into non-concurrent
NSOperation
the reason is to allow necessarily unarchive actions on the streaming date
so

- (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 ?



-- 
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


Re: asynchronous nsurlconnection in nsoperation

2012-03-21 Thread Alex Zavatone
Is this for iOS or Mac OS?

I've used Grand Central Dispatch and [NSURLRequest requestWithURL:[NSURL 
URLWithString:urlString]]; 

The second example is synchronous.

There is also:
  NSData  *response_NSData   = [NSURLConnection 
sendSynchronousRequest:my_NSURLRequest  returningResponse:my_NSURLResponse 
error:my_NSError];
and

sendAsynchronousRequest:queue:completionHandler:
Loads the data for a URL request and executes a handler block on an operation 
queue when the request completes or fails.

+ (void)sendAsynchronousRequest:(NSURLRequest *)request queue:(NSOperationQueue 
*)queue completionHandler:(void (^)(NSURLResponse*, NSData*, NSError*))handler

Look up the above in the NSURLConnection Class Reference

And also this, but disregard the older stuff.

http://www.raywenderlich.com/4295/multithreading-and-grand-central-dispatch-on-ios-for-beginners-tutorial

Here is my GDC stuff.

- (void)viewDidLoad {
NSLog(@In viewDidLoad);
[super viewDidLoad];
//NSString * const kRootURLString = @http://10.6.2.137/;;
NSURL *wordsURL = [NSURL 
URLWithString:@http://localhost/~zav/Offices.txt?;];

NSURL *myUrl = [NSURL URLWithString:URLstring];
// dispatch_async(kBgQueue, ^{ NSData* data = [NSData 
dataWithContentsOfURL: myUrl]; // THIS IS WHAT YOU WANT Ariel **
  dispatch_sync(kBgQueue, ^{ NSData* data = [NSData 
dataWithContentsOfURL: myUrl]; // doing a sync dispatch here - we want to wait 
for it to finish
  [self performSelectorOnMainThread:@selector(fetchedData:) 
withObject:data waitUntilDone:YES];
  });

// Uncomment the following line to display an Edit button in the navigation 
bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}

...

- (void)fetchedData:(NSData *)responseData {
 
 NSLog(@In fetchedData);
NSLog(@ );

// log URL data
NSString* newStr = [[NSString alloc] initWithData:responseData 
encoding:NSUTF8StringEncoding];
NSLog(@%@, newStr);   
}

Practice on a few simple cases until you find a method that you like.  Note 
that I haven't checked my code for any leaks.  This is old play code from 2 
weeks ago.

On Mar 21, 2012, at 11:59 AM, 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
 so
 
 - (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 ?
 
 
 
 -- 
 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/zav%40mac.com
 
 This email sent to z...@mac.com

- Alex Zavatone



___

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


Re: asynchronous nsurlconnection in nsoperation

2012-03-21 Thread Sebastian Celis
On Wed, Mar 21, 2012 at 10:59 AM, Ariel Feinerman arielfap...@gmail.com wrote:
 I wish to insert an asynchronous NSURLConnection into non-concurrent
 NSOperation

Hi Ariel,

MBRequest does this. It is done by forcing the operation's runloop to
continue running while the network connection is in progress. I would
recommend looking though the source code. Specifically, take a look at
MBURLConnectionOperation.

https://github.com/mobiata/MBRequest
https://github.com/mobiata/MBRequest/blob/master/Classes/MBURLConnectionOperation.m

- Sebastian
___

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