How to lock a method when using multithreading? - iphone

how can I stop 2nd thread to access same method that is being used by first thread?

One option is to use #synchronized in the method.
- (NSString *)someMethod {
#synchronized(self) {
// do some work
}
}
It allows the method to be called but will synchronize on itself and protect it's work (and more importantly the data it's working on).

Have a look at NSLock.
https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSLock_Class/Reference/Reference.html
Just found it when looking for a C# lock statement, it appears to do the same thing..
There is also another SO thread relating to synchronisation:
How does #synchronized lock/unlock in Objective-C?

Related

iphone,how to create NSOperationQueue

I've got a couple background tasks to process while still keeping the UI responsive. I started down the path of creating and managing threads, but soon came across the NSOperations. Sounds like a better solution . . .
However, I cannot seem to get a reference to the NSOperationQueue. The Threading Programming Guide suggests the following
#implementation MyCustomClass
- (void)launchTaskWithData:(id)data
{
NSInvocationOperation* theOp = [[NSInvocationOperation alloc] initWithTarget:self
selector:#selector(myTaskMethod:) object:data];
// Add the operation to the internal operation queue managed by the application delegate.
[[MyAppDelegate sharedOperationQueue] addOperation:theOp];
}
// This is the method that does the actual work of the task.
- (void)myTaskMethod:(id)data
{
// Perform the task.
}
. . . but I (and more importantly, the compiler) don't see the 'sharedOperationQueue' message when I implement the code in my app.
What am I missing?? Is sharedOperationQueue deprecated and no longer available? How can I get an NSOperationQueue reference?
sharedOperationQueue is not part of the official API. It is a custom method you are supposed to implement yourself, in this example as a class method in your app delegate class. The method should create and return NSOperationQueue or, if it already has created the queue, simply return the existing one.
How you implement this in your case is up to you. You don't have to follow the example. Simple create an operation queue with alloc/init (no magic here) and store a reference to it in a property so that you can later release it when you no longer need it.
Cocoa Is My Girlfriend has a good tutorial, this will help you to use NSOperationQueue.
You have to declare application delegate before adding operation:
AppDelegateClass * MyAppDelegate = [NSApp delegate];

In IPhone How to use multithreading with static methods in NSThread

I an developing an iPhone application in that,I am trying to download multiple files simultaneously from ftp server with threads.but my method to download is written in header file and that method is static.so if i try to access that method with to threads then variables of method for first thread are overridden by variables of first thread.Please suggest me how to synchronize the two threads in this case.
I was suffering from the same problem and i solved it by using code like this
Where you are telling the target for dedatching the method to thread you should use [Myclass class]
Example:
[NSThread detachNewThreadSelector:#selector(startSpinner) toTarget:[MyappDelegate class] withObject:nil];
Hope this helps.

Stop lazy-loading images?

Here's the issue – I followed along with the Apple lazy-load image sample code to handle my graphical tables. It works great. However, my lazy-load image tables are being stacked within a navigation controller so that you can move in and out of menus. While all this works, I'm getting a persistent crash when I move into a table then move immediately back out of it using the "back" button. This appears to be a result of the network connections loading content not being closed properly, or calling back to their released delegates. Now, I've tried working through this and carefully setting all delegates to nil and calling close on all open network connections before releasing a menu. However, I'm still getting the error. Also – short posting my entire application code into this post, I can't really post a specific code snippet that illustrates this situation.
I wonder if anyone has ideas for tasks that I may be missing? Do I need to do anything to close a network connection other than closing it and setting it to nil? Also, I'm new to debugging tools – can anyone suggest a good tool to use to watch network connections and see what's causing them to fail?
Thanks!
Have you run it through the debugger (Cmd-Y)? Does it stop at the place where the crash is happening? That should show you in code where the issue is happening. I'm betting the issue has to do with over-releasing something rather than cleaning up connections. Are you getting EXC_BAD_ACCESS? Check any delegates and make sure they are nil when -viewWillDisappear gets called. That way, if anything tries to call back to a delegate, it will just be a no-op.
You may also want to try enabling zombies (NSZombieEnabled) which will tell you when an object that has been released is being accessed again. It's very helpful in finding over-released objects.
Ah ha... after a large zombie hunt (thanks, Matt Long), I discovered that the issue stems from an error in Apple's LazyTableImages sample code. That example provides the following implementation for canceling all image loads, which I turned into a general-purpose stopAllImageLoads method...
From RootViewController.m in LazyTableImages sample code:
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// terminate all pending download connections
NSArray *allDownloads = [self.imageDownloadsInProgress allValues];
[allDownloads performSelector:#selector(cancelDownload)];
}
There is in error in the last line of the above method where performSelector is called on an array of objects. The above implementation calls the selector on the array itself, rather that on each object in the array. Therefore, that last line should be this:
[allDownloads makeObjectsPerformSelector:#selector(cancelDownload)];
Once that line was changed, everything else fell into place. It turns out I wasn't calling my stopAllImageLoads method where I meant to – I had disabled it at one point because it was causing an error. Once that was back in place, the memory issues cleared up because image loads were successfully canceled before the table delegate was released.
Thanks all for your help.
If you're doing ANY asynchronous function (network requests, Core Location updates, etc), you run the risk that your view controller that is the delegate of that action is deallocated by the time the async function returns. i.e. you back out of the view and take the delegate target away from the background process. I've dealt with this several times.
Here's what you do. Use the ASIHTTPRequest library (which you should be doing anyway--it's brilliant). Create a synthesized property to hold your request. Then in viewWillDisappear, call -cancel on your request. To be safe, I also set its delegate to nil, but that should be unnecessary.
Here's a sketch of what you want to do. Note I typed this right here, haven't syntax-checked it or anything.
#implementation MyViewController
#synthesize req //this is an ASIHTTPRequest *req.
-(void)viewDidLoad
{
//make an NSURL object called myURL
self.req = [ASIHTTPRequest requestWithURL:myURL];
self.req.delegate = self;
[self.req startAsynchronous];
}
-(void)viewWillDisappear
{
[self.req cancel];
}
-(void)requestFinished:(ASIHTTPRequest *)request
{
NSString *string = [request responseString];
}

What thread are iphone delegate methods run in for webview and core location callbacks?

I have an issue that looks like a race condition with a webview callback and a location manager callback that interact with the same variables and an alert dialog - the dialog is created in the location callback and should be dismissed in the webview callback. I thought that the delegate callbacks for standard objects like the webview and core location would be run in the main thread - is that not correct?
If in doubt then you can do something like this:
- (void) someCallback
{
if ([NSThread isMainThread] == NO) {
[self performSelectorOnMainThread: #selector(someCallback)];
}
}
To make sure that you are always executing callback methods on the main thread and thus preventing concurrency issues.
You can also use a #synchronized block of course, but in my experience it is much better to rely on the synchronous nature of executing methods on the main thread.

Recommended thread layer to use for iPhone development?

I'm new to Objective C, and Mac development... It appears that I can use the Posix threads API in my app.. Is this the recommended way? Or is their some Apple API I should be using for mutexes, condition variables and threads instead?
I should add that I'm developing for the iPhone.
I'd like to add exactly what I'm trying to do. Basically, CoreLocation is asynchronous... You tell it to start updating you, and then it just calls an update method on you periodically...
The problem I have is that I need another thread to block until an update occurs... How can I make the main application thread block until at least one CoreLocation update occurs? Is their an NSConditionVariable? :)
I'd suggest an even easier way to get stuck into threads is to use the following call:
[self performSelectorInBackground:(#selector(myMethod)) withObject:nil];
This will automatically create a new background thread for you to run in. Incidentally make sure you do the following inside your background method:
-(void) myMethod {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// code you want to run in background thread;
[pool drain];
}
This is necessary because there isn't a default autorelease pool set up for any threads except the main one.
Finally, talking about blocking the main thread, you could use the following from your background thread to do this:
[self performSelectorOnMainThread:(#selector(myOtherMethod)) withObject:nil waitUntilDone:YES];
The optional third parameter will hold up the main thread for you if you want it to do so.
Hope that helps!
It depends on what you are trying to do, but I would start with NSOperation and NSOperationQueue. It makes it pretty simple to hand off background tasks. Take a look at Dave Dribin's blog post on NSOperation concurrency as well: http://www.dribin.org/dave/blog/archives/2009/05/05/concurrent_operations/
Instead of blocking the user interface by making it hang, I would suggest showing some kind of loading screen until you've received your first update. The could would look something like this:
- (void)viewDidLoad {
...
[myCLLocationManager beginUpdates];
[self showLoadingIndicator];
....
}
- (void)locationManager:(CLLocationManager *)manager didReceiveUpdates {
[self hideLoadingIndicator];
// Additionally load the rest of your UI here, if you haven't already
}
Don't quote me on those method calls verbatim, but that's how I suggest solving your problem, in essence.
Yes there is an NSCondition object, and it will probably do exactly what you want for the CoreLocation scenario you mentioned.