iphone - stopping a method that is running? - iphone

i have a [self parseXMLFileAtURL:path] method. is there anyway of stopping it midway? like terminating the method.
Reason for doing is because im running an apache http server on one pc and if the server is not running, the app will 'hang' if this method is called. so i want to to something like terminating the method after a certain amount of seconds , 5s maybe. and display an alert message.

I'd have two suggestions... one, if you possibly can, use NSMutableURLRequest with NSURLConnection to retrieve the data; which gives you much better control over things like timeout.
NSError * error;
NSURLResponse * response;
NSMutableURLRequest * request = [NSMutableURLRequest
requestWithURL:[NSURL URLWithString:#"http://..."]
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:60.0];
// Not sure if you need this, but I frequently do POSTs as well, so whatever:
[request setHTTPMethod:#"GET"];
NSData * responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSString * xml = [[[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding] autorelease];
(NB: You'll have to check the error response, I just omitted it for clarity)
Also, ideally (since in my example I use the synchronous method) this should be run on a background thread... but I found it much easier to run this on the background thread manually using "performSelectorInBackground:" and use the synchronous methods, than I did using the async methods. Keep in mind, you'll have to create your own auto release pool if you do that... but that's two lines, and it's super easy.
Short of that, it IS possible to terminate the method... you'd have to run it on a different thread, and kill the thread if it took too long... but really, the NSMutableURLRequest isn't so bad, and it already gives you the timeout options you're looking for.
The thread programming guide at: http://developer.apple.com/iphone/library/documentation/cocoa/Conceptual/Multithreading/CreatingThreads/CreatingThreads.html#//apple_ref/doc/uid/10000057i-CH15-SW2 talks about killing threads... and tells you (indirectly) how to do it... but if you simply kill the thread, you are almost guaranteed to leak something.

I'm pretty sure that you could try installing a signal handler with sigaction to handle SIGALRM and use the alarm function. There is, however, probably a better solution using the Cocoa framework. I'll leave this here, but it's probably not the easiest way.

A method is just a C(++) function, so there really no way to stop it.

Related

NSOperation and NSURLConnection conflicts

What is the best way to run code on a separate thread?
NSInvocationOperation *operationToComplete = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(operationMethod) object:nil];
NSOperationQueue *queueToStart=[[NSOperationQueue alloc] init];
[queueToStart addOperation:operationToComplete];
-(void) operationMethod
{
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&_response error:&_error];
}
OR:
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request
delegate:self];
I've been doing the second way but am little bit confuse regarding this or use another way to do this.
Using operation queues with synchronous requests can be especially useful if you have many concurrent requests that you want to invoke. Operation queues make it easy to not only specify concurrent operation, but also to specify maxConcurrentOperationCount to constrain how many concurrent operations you want to run (which is important if you're firing off a whole bunch of them as you're limited to how many can operate concurrently with a given server).
Your latter example, with initWithRequest, is useful if you need the NSURLConnectionDataDelegate methods (for any of a number of reasons, e.g. you want to update progress view, you want to perform some streaming operations, you want to be able to cancel connection, etc.).
A third approach is to marry the initWithRequest approach with an NSOperationQueue, namely to wrap the NSURLConnection in its own NSOperation. This marries these two techniques, providing the richness of NSURLConnectionDataDelegate methods (cancelable, progress updates, etc.), with the power of operation queues (the ability to add network requests to queue for which you can configure degree of concurrency, establish dependencies between operations, etc.), but providing a nice interface. There are some idiosyncrasies to properly implement this approach (you have to schedule/create a runloop for NSURLConnection if you use it in an NSOperationQueue). I might, therefore, advise using a third party library, such as AFNetworking, if you want to enjoy the richness of this technique without getting lost in the implementation details.
In answer to your question of "which is best", it just depends upon what you're trying to do, as they all have pros and cons. But I prefer a NSOperation-based NSURLConnection, and would generally advise using AFNetworking if you want to simplify your development effort.
By the way, you can probably simplify the first example:
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperationWithBlock:^{
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&_response error:&_error];
}];
Using Grand Central Dispatch (GCD) you can run code in background, which one is easier also.
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
});
And also NSURLConnection supports two modes of operation: asynchronous and synchronous. Neither uses separate threads at all.

ASIHTTPRequest / ASIFormDataRequest - referencing request object within blocks under ARC

Very similar to this question, I am trying to convert a project that uses ASIHTTPRequest & ASIFormDataRequest to ARC.
In my view controller classes, I often refer to and use properties of the request object in the completion blocks (looking at the response code, response data etc):
__block ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:[NSURL URLWithString:SOME_URL]];
[request setCompletionBlock:^{
if([request responseStatusCode] == 200) ....etc
When converting to ARC I get the warning:
Capturing 'request' strongly in this block is likely to lead to a
retain cycle
What is the proper way to do this?
Another SO user notes in the previous thread that simply adding __weak may cause the request to be released before the completion of the block, which I believe to be true.
How can I properly reference these properties in completion/failure blocks under ARC?
(I read your comment to the other question)
After implementing a few more modules using ASIHTTPRequest, I learned that the best way was to keep a strong reference to your request object. In your case, you can do:
self.request = [ASIFormDataRequest requestWithURL:[NSURL URLWithString:SOME_URL]];
__weak ASIFormDataRequest *weakRequest = self.request; // __block directive not needed since we only access the instance's properties.
[self.request setCompletionBlock:^{
if([weakRequest responseStatusCode] == 200)
// ...
This way you can still control self.request even after you start the request (e.g. for cancelling). You can do self.request = nil; when you're ready to release your request, maybe inside your completion block or self.request's parent object's cleanup methods.
Update:
If you're targeting pre-iOS 5, then the common ground stands: use __unsafe_unretained instead of __weak. This is OK because looking at ASIHTTPRequest.m, the blocks are nil'ed out in its dealloc() (i.e. they shouldn't get executed). Although I haven't tested that yet, so make sure to still test with NSZombies enabled.
Note:
The only safe way to cancel an ASIHTTPRequest object is to call its clearDelegatesAndCancel method. I've been bitten by some nasty bugs when I was just using the plain cancel one.
If you're targeting iOS versions before 5.0, that do not include weak support:
__unsafe_unretained __block ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
I've found this answer to be helpful: https://stackoverflow.com/a/7735770/133875
It says to use __unsafe_unretained as well as __block

Is there any issue if I used sync connections in iPhone?

I know that the pattern in iPhone is to use ASync connection calls (using the informal protocols that is implemented by the current class).
In my case, I've created a utility class to do the networking staff and then return the data to the ViewController.
I find is inadequate to implement the connection model as Async in a utility class because r I will write a block of code in the ViewControlle such following: (which IMHO is bad)
MyUtilityConnection* utilConn = ....
while (true)
{
if ([utilConn checkUnderlyingAsyncConnectionFinishedLoading]) break;
}
NSData* dataFromUrl = [utilConn dataFromUnderlayingConn];
So, the question is, Does using Sync connection model in iPhone could causes problem? and solutions?
(What about the drawing will stril hanging until the data come???)
AVOID by all means to do synchronous connections! This will obviously freeze your UI (and it gets worse if you don't have a good bandwidth of course).
What you could do is to use the blocks syntax to write more readable code when you need to download data. Create a class that implements the NSURLConnection delegate methods, and then call the block when the data is done.
See my OHURLLoader class on github for example that does exactly that (and that's only one solution).
Usage example:
NSURL* url = ...
NSURLRequest* req = [NSURLRequest requestWithURL:url];
OHURLLoader* loader = [OHURLLoader URLLoaderWithRequest:req];
[loader startRequestWithCompletion:^(NSData* receivedData, NSInteger httpStatusCode) {
NSLog(#"Download of %# done (statusCode:%d)",url,statusCode);
outputTextView.text = loader.receivedString;
} errorHandler:^(NSError *error) {
NSLog(#"Error while downloading %#: %#",url,error);
outputTextView.text = [error localizedDescription];
}];
During sync methods (sendSynchronousRequest:returningResponse:error:) the UI is non-responsive (assuming that the sync method is called on the main thread).
But they are fine on background threads, the easiest way to accomplish sync calls on a background thread is with GCD.

Creating multiple NSURLConnections. How to identify which Async call

I am intending to create 2 requests using NSURLConnection. When the server responds and calls connectionDidFinishLoading it passes in the connection as the parameter, but how do I identify which connection is passed in?
Save both NSURLConnection objects as member variables of whatever delegate object you passed to connectionWithRequest:delegate:. Then you can just compare each of those to the NSURLConnection passed to connectionDidFinishLoading:, and respond appropriately:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
if (connection == firstConnection) {
// do something
}
else if (connection == secondConnection) {
// do something else
}
}
Another slightly more object-oriented option would be to create two different delegate objects, each of which knows how to deal with each each type of connection. Then just pass the appropriate delegate when you create each connection. That way you don't need to check to see which connection you have, because each delegate will only receive connectionDidFinishLoading: for its own connection.
I prefer different delegates for each connection, too. Although it's a bit of overhead. Fortunately, you can simplify things by using blocks. It's a new feature that doesn't exist in standard SDK yet, but there is 3rd-party framework called PLBlocks that you can use already. Here is an article on how to use them, it also contains example for NSURLConnection.
This is the client code making HTTP request with block callback:
NSURLRequest *req = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.google.com"]];
[NSURLConnection sendAsynchronousRequest:req onCompletionDo: ^(NSData *data, NSURLResponse *res, NSError *err) {
NSLog(#"data: %ld bytes. res: %#, error: %#", (long)[data length], res, err);
[cell.activity stopAnimating];
}];
I used to create a custom wrapper around NSURLConnection, too, but I've now switched over to ASIHTTPRequest. This is a fantastic library providing much more flexibility and features than NSURLConnection. Have a look and give it a try, it's really worth it.
What I do in my projects is create a wrapper class for the connection. This way, you can keep a new instance for each connection you need, and maintain these classes in another manager class.
Something like [AsynchronousConnection initWithURL:delegate:selector:]
Then you can be ensure the right thing is called when the NSURLConnection is done/failed.
Please do not refer https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSURLConnection_Class/Reference/Reference.html
GO to the NSURLConnection.h file and you will find the following.
When created, an NSURLConnection performs a deep-copy of the
NSURLRequest. This copy is available through the -originalRequest
method. As the connection performs the load, this request may change
as a result of protocol canonicalization or due to following
redirects. -currentRequest can be used to retrieve this value.
Ultimately [connection currentRequest].URL absoluteURL might help.
Regards,
PRASANNA.

Downloading multiple files in iphone app(Objective c)

In my iPhone app I want to download multiple files which are on IIS with authentication. On a button click i want to start the downloading process.
I know how to download a file with authentication.
NSURLRequest* request =
[NSURLRequest requestWithURL:mMovieURL
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
movieConnection =
[[NSURLConnection alloc] initWithRequest:request delegate:self ];
and i have couple of delegate methods with the above code.
But how to do it with mutliple downlaods going at the same time.
Thanks,
I'm not familiar with MultipleDownload, but in case it doesn't meet your needs, the issue I take it is that you have a single object that is the delegate to many NSURLConnections, and you want to know how to keep them straight.
The delegate methods all return the NSURLConnection itself as their first parameter. So you can keep track of which data goes where by testing which NSURLConnection is calling you back. One way to do this is with an NSDictionary that maps the connection to its NSMutableData object. Now the trick is that you can't make an NSURLConnection be the key in a dictionary because it doesn't conform to NSCopying (and you wouldn't want it to). One way to work around this is to use the address of the connection such as:
NSString *key = [NSString stringWithFormat:#"%p", connection];
This will return a unique key for any object (the hex representation of its address). Some people use description for this purpose, but I don't like that because it's not a well defined interface. There's no promise that it be unique. In systems where I do this a lot, I implement the above -stringWithFormat: in a method called -uniqueIdentifier and make it a category on NSObject so anything can be tracked in a dictionary.
I often find it's easier just to create a small wrapper object so that each object controls its own NSURLConnection, much as I'm sure MultipleDownload is doing, but still this technique is useful in a variety of cases, whether you're managing multiple tableviews, or anything else that has a delegate.
EDIT: Replaced %x I had above with %p as noted by Peter. He's right, and I wasn't thinking correctly. Double-checking my code, I actually have been using %p, having run into this error before....
I've done this before when I wanted to download 10 XML files at the same time (it was much faster than queuing them to download one after the other). I used the libraries found here:
http://github.com/leonho/iphone-libs/tree/master
They were easy to implement and there's some example code on the front page to get you started.
self.urls = [NSMutableArray arrayWithObjects:
#"http://maps.google.com/maps/geo?output=json&q=Lai+Chi+Kok,Hong+Kong",
#"http://maps.google.com/maps/geo?output=json&q=Central,Hong+Kong",
#"http://maps.google.com/maps/geo?output=json&q=Wan+Chai,Hong+Kong",
nil];
self.downloads = [[MultipleDownload alloc] initWithUrls: urls];
self.downloads.delegate = self;
Good luck.
I think the simplest way to do this is to use NSOperation - and a NSOperationQueue.
This will mean that you can specifiy if each operation should happen sequentially or in parallel. You can even limit the number of parallel operations - so that there are a max of 5 (say) running at one time time and then other operations queue up behind.
This really is a great way of letting the OS handle multiple activities - and works well with the lazy loading type philosophy of the iPhone OS.
You can then get each operation to make a call back as it finishes - or even make progress callbacks on the main thread.
I have changed my code to all work this way now and found it to be much more robust and user firendly.
I'm not familiar with
MultipleDownload, but in case it
doesn't meet your needs, the issue I
take it is that you have a single
object that is the delegate to many
NSURLConnections, and you want to know
how to keep them straight.
The delegate methods all return the
NSURLConnection itself as their first
parameter. So you can keep track of
which data goes where by testing which
NSURLConnection is calling you back.
One way to do this is with an
NSDictionary that maps the connection
to its NSMutableData object. Now the
trick is that you can't make an
NSURLConnection be the key in a
dictionary because it doesn't conform
to NSCopying (and you wouldn't want it
to). One way to work around this is to
use the address of the connection such
as:
NSString *key = [NSString
stringWithFormat:#"%p", connection];
A better way would be to use NSValue with the valueWithNonretainedObject constructor. That way you can access the key object from the NSDictionary if you have to.
NSURLConnection is asynchronous and init exits immediately. Just run it multiple times.
NSArray *connections = [[NSArray alloc] initWithObjects:
[[NSURLConnection alloc] initWithRequest:request1 delegate:self ],
[[NSURLConnection alloc] initWithRequest:request2 delegate:self ],
[[NSURLConnection alloc] initWithRequest:request3 delegate:self ],
[[NSURLConnection alloc] initWithRequest:request4 delegate:self ],
nil];