call a function using thread in xcode - objective-c

i have created a thread in xcode and i have given the function name to be called from that thread.
but my problem is that the function name which is given to call is not being called(came to know when put a breakpoint in that function)
code:
NSThread* myThread;
[myThread start];
[self performSelector:#selector(func1:) onThread:myThread withObject:nil waitUntilDone:false]
and later i tried this one also:
NSThread* myThread = [[NSThread alloc] initWithTarget:self selector:#selector(func1:)object:nil];
[myThread start];
above func1 is the name of the function to be called.
so can any one please tell me how to create the thread and call func1 from there....

In your first code sample it doesn't look like you are actually creating a new thread. You create an empty myThread variable and then call start on it but this will just result in start being sent to nil. The empty thread variable is then sent to the performSelector:onThread:withObject:waitUntilDone: method which will presumably do nothing.
You will need to properly create a thread before you can actually run something on it using performSelector:onThread:withObject:waitUntilDone:.
Alternatively, it would be much easier, assuming you don't care which background thread the method runs on, to simply use performSelectorInBackground:withObject:. For example:
[self performSelectorInBackground:#selector(func1:) withObject:nil];

Try the following if it works:
[NSThread detachNewThreadSelector:#selector(func1) toTarget:self withObject:nil];
Since you are not passing any object to your "func1" (aka: your method doesn't have parameters) you don't need to put the ":" after its name.

If your func1 accepting one argument. Then definitely it has to work with second approach which you used. May be your fuc1 has no formal argument and still u calling in selector like this #selector(fuc1:) and passing object as a nil. so may be due to this reason it is not working. It can be one reason. just try it if not.

Related

A nice way to perform a selector on the main thread with two parameters?

I'm searching for a nice way to perform a selector on the main thread with two parameters
I really like using
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait
method, except now I have two parameters.
So basically I have a delegate which I need to notify when the image is loaded:
[delegate imageWasLoaded:(UIImage *)image fromURL:(NSString *)URLString;
But the method where I do this might be invoked in the background thread, and the delegate will use this image to update the UI, so this needs to be done in the main thread. So I really want the delegate to be notified in the main thread as well.
So I see one option - I can create a dictionary, this way I have only one object, which contains two parameters I need to pass.
NSDictionary *imageData = [NSDictionary dictionaryWithObjectsAndKeys:image, #"image", URLString, #"URLstring", nil];
[(NSObject *)delegate performSelectorOnMainThread:#selector(imageWasLoaded:) withObject: imageData waitUntilDone:NO];
But this approach does not seem right to me. Is there more elegant way to do this? Perhaps using NSInvocation?
Thanks in advance.
Using an NSDictionary to pass multiple parameters is the right way to go about it in this case.
However, a more modern method is to use GCD and blocks, this way you can send messages to an object directly. Also, it looks as if your delegate method might be doing something UI updates; which you are correctly handling on the main thread. With GCD you can do this easily, and asynchronously like this:
dispatch_async(dispatch_get_main_queue(), ^{
[delegate imageWasLoaded:yourImage fromURL:yourString;
});
Replace your performSelector:withObject call with this, and you won't have to mess around with changing your method signatures.
Make sure you:
#import <dispatch/dispatch.h>
to bring in GCD support.
Since you don't have access to GCD, NSInvocation is probably your best choice here.
NSMethodSignature *sig = [delegate methodSignatureForSelector:selector];
NSInvocation *invoke = [NSInvocation invocationWithMethodSignature:sig];
[invoke setTarget:delegate]; // argument 0
[invoke setSelector:selector]; // argument 1
[invoke setArgument:&arg1 atIndex:2]; // arguments must be stored in variables
[invoke setArgument:&arg2 atIndex:3];
[invoke retainArguments];
/* since you're sending this object to another thread, you'll need to tell it
to retain the arguments you're passing along inside it (unless you pass
waitUntilDone:YES) since this thread's autorelease pool will likely reap them
before the main thread invokes the block */
[invoke performSelectorOnMainThread:#selector(invoke) withObject:nil waitUntilDone:NO];
Following method can also be used:
- (id)performSelector:(SEL)aSelector withObject:(id)anObject withObject:(id)anotherObject
As per the docs of this method-
Invokes a method of the receiver on the current thread using the default mode after a delay.
Yes, you've got the right idea: you need to encapsulate all the data you want to pass to the delegate on the main thread into one single object which gets passed along via performSelectorOnMainThread. You can pass it along as a NSDictionary object, or a NSArray object, or some custom Objective C object.

Run an anonymous block on a specific background thread

At first glance it seemed like an easy question, but I just can't figure how to run an anonymous block on a certain background thread i.e. I am looking for the blocks equivalent of -performSelector:onThread:withObject:waitUntilDone:.
Related: Is it possible to associate a dispatch queue with a certain background thread, just like the main queue is associated with the application's main thread?
Edit Clarified that I am looking to run an anonymous block
I saw this function RunOnThread() recently in Mike Ash's PLBlocksPlayground (zip file, see BlocksAdditions.m):
void RunOnThread(NSThread *thread, BOOL wait, BasicBlock block)
{
[[[block copy] autorelease] performSelector: #selector(my_callBlock) onThread: thread withObject: nil waitUntilDone: wait];
}
This is what I was looking for.
There are a bunch of other very useful blocks related utilities in PLBlocksPlayground, most of which Mr. Ash explains in this post.
If I understand you right you should do this:
dispatch_queue_t thread = dispatch_queue_create("your dispatch name", NULL);
dispatch_async(analyze, ^{
//code of your anonymous block
});
dispatch_release(thread);
You also can write some method, which will take block to it, but you should know what type of parameters will it holds:
-(void)performBlock:(void (^)(SomeType par1, SomeType par2))block ToData:(Sometype)data;
You can call it with anonymous block:
[something performBlock:^(SomeType par1, SomeType par2){
//do your stuff
} ToData: data]
And in method you can call your block as a simple C function:
block(par1, par2);
A block is a function. Call it like you would call any other function.

iOS performSelectorOnMainThread with multiple arguments

I would like to perform a selector on the main thread from another thread, but the selector has multiple arguments, similar to this:
-(void) doSomethingWith:(int) a b:(float)b c:(float)c d:(float)d e:(float)e {
//...
}
How can I get this working with performSelectorOnMainThread: withObject: waitUntilDone:?
EDIT
I would like to explain why i need this.
I'm working with UIImageViews on the main thread, and I make the calculations for them on another thread. I use a lot of calculations so if i make everything on the main thread, the app lags. I know that UI elements can only be manipulated on the main thread, this is why i would like it to work this way, so the main thread can listen to touch events without lags.
When you're using iOS >= 4, you'd do this instead:
dispatch_async(dispatch_get_main_queue(), ^{
[self doSomething:1 b:2 c:3 d:4 e:5];
});
That's like doing waitUntilDone:NO. If you want to wait until the method is finished, use dispatch_sync instead.
You'll need to use a NSInvocation
Create the object, set the target, selector and arguments.
Then, use
[ invocationObject performSelectorOnMainThread: #selector( invoke ) withObject: nil, waitUntilDone: NO ];
you can pass one object of NSDictionary/NSArray type having required arguments.
and accept the same type of object in your function.
then, decompose the values and proceed with processing.
you have to use NSNumber for numeric values for adding them to NSarray/NSDictionary and later on in your function, you can convert them back with intValue/floatValue etc
best of buck.

NSThread reading parent's ivars?

I detach a new NSThread withObject:self so that the thread can callback the main thread as a delegate. However, I also need the new thread to be able to read some values in the parent. With NSThread, I can only pass one object withObject, and I'm using that to pass self because of the delegate methods. Is there a way my new thread can read values from it's parent? Perhaps through the self object that is passed to it?
Here's where I launch the thread:
MulticastDaemon* multicastDaemon = [[MulticastDaemon alloc] init];
[NSThread detachNewThreadSelector:#selector(doWorkWithDelegate:)
toTarget:multicastDaemon
withObject:self];
I want to pass a multicast IP address and port number to the daemon, so he knows what to listen on, but I'm not sure how to get those values to multicastDaemon.
How can multicastDaemon access those values?
Yes, you can access the variables by making them properties and then doing something like this (you don't say what the class is that this call is made from, so I've called it MyClass):
#implementation MulticastDaemon
-(void) doWorkWithDelegate:(MyClass*) cls
{
cls.value1 = 12;
...
}
...
#end
EDIT: Corrected implementation.
You'd better use the subclass of NSOperation and then add it to the NSOperationQueue. You can add any additional parameters to that operation subclass.
There is also another advantage of NSOperation over NSThread. NSOperation and NSOperationQueue are build on top of the GCD and threading is far more optimal then NSThread.
But you can also simply add some properties to your MulticastDaemon.
You can change your MulticastDaemon's interface slightly so that you set the delegate before creating the new thread. Then you free up the withObject: slot to pass something else along. This avoids accessing variables across threads.
Either:
MulticastDaemon* multicastDaemon = [[MulticastDaemon alloc] initWithDelegate:self];
[NSThread detachNewThreadSelector:#selector(doWorkWithInformation:)
toTarget:multicastDaemon
withObject:operatingInfo];
Or
MulticastDaemon* multicastDaemon = [[MulticastDaemon alloc] init];
[multicastDaemon setDelegate:self];
Otherwise, you'll have to create a method that the daemon can call on its delegate that gathers and packages up the information to pass back. In that case, you'll probably have to start worrying about thread safety.

ObjC delegate methods never gets called

I am creating instances of a class FlickrImage parsing a Flickr API photos response. The class has a method getLocation that does another API call to get the geolocation:
NSLog(#"getting location for %i",self.ID);
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
OFFlickrAPIRequest *flickrAPIRequest = [[OFFlickrAPIRequest alloc] initWithAPIContext[appDelegate sharedDelegate].flickrAPIContext];
[flickrAPIRequest setDelegate:self];
NSString *flickrAPIMethodToCall = #"flickr.photos.geo.getLocation";
NSDictionary *requestArguments = [[NSDictionary alloc] initWithObjectsAndKeys:FLICKR_API_KEY,#"api_key",self.ID,#"photo_id",nil];
[flickrAPIRequest callAPIMethodWithGET:flickrAPIMethodToCall arguments:requestArguments];
[pool release];
I have implemented the callback method that would catch the response from the API and update the FlickrImage instance with the geolocation data - but it never gets called. Here's where the instances get created:
NSDictionary *photosDictionary = [inResponseDictionary valueForKeyPath:#"photos.photo"];
NSDictionary *photoDictionary;
FlickrImage *flickrImage;
for (photoDictionary in photosDictionary) {
flickrImage = [[FlickrImage alloc] init];
flickrImage.thumbnailURL = [[appDelegate sharedDelegate].flickrAPIContext photoSourceURLFromDictionary:photoDictionary size:OFFlickrThumbnailSize];
flickrImage.hasLocation = TRUE; // TODO this is actually to be determined...
flickrImage.ID = [NSString stringWithFormat:#"%#",[photoDictionary valueForKeyPath:#"id"]];
flickrImage.owner = [photoDictionary valueForKeyPath:#"owner"];
flickrImage.title = [photoDictionary valueForKeyPath:#"title"];
[self.flickrImages addObject:[flickrImage retain]];
[flickrImage release];
[photoDictionary release];
}
The retain is there because I thought it might help solve this but it doesn't - and doesn't the NSMutableArray (flickrImages is a NSMutableArray) retain its members anyway?
EDIT I should add that the getLocation method (first code snippet) is launched in a thread:
[NSThread detachNewThreadSelector:#selector(getLocation) toTarget:self withObject:nil];
Your delegate method is never being called because the request is never being made. When you call callAPIMethodWithGET:, it sets up communications to run asynchronously on the current thread's run loop, then returns immediately. That way you can safely call it on the main thread without blocking.
Because you are calling the method from a thread you created yourself, it does not see the main run loop, but the run loop for your new thread. However, because you never execute the run loop, the messages are never sent, a response is never received, and your delegate is never called.
You could fix this by calling [[NSRunLoop currentRunLoop] run] in your new thread. That will let the work happen. But in this case would be easier to never detach a new thread in the first place. Your program won't block, and you won't have to worry about your delegate method needing to be reentrant.
I've also run into this problem when requesting and parsing XML on a different thread my solution was to do this:
while([[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:start] && !isFinished){
}
Where start = [NSDate dateWithTimeIntervalSinceNow:3]; this is basically a timeout so that it doesn't live forever and isFinished is set to true when my parsing has completed.
I'm not familiar with these flicker API wrappers, but in this code:
NSDictionary *requestArguments = [[NSDictionary alloc] initWithObjectsAndKeys:FLICKR_API_KEY,#"api_key",self.ID,#"photo_id",nil];
Are you certain that both FLICKR_API_KEY, and self.ID are not nil? If either of them is nil, you'll end up with a dictionary that has less items in it than you intend.
Could you post the callback method(s) you have implemented – this could be just down to a simple typo, as it appears OFFlickrAPIRequest won’t do anything if the delegate does not implement the required callback.
Did you also implement flickrAPIRequest:didFailWithError: to see if there was an error returned from the API call?
Okay, I did solve it, with help from some of the suggestions above.
I did remove the extra retain because it did in fact create a memory leak. It did not look right from the outset, so my gut feeling about that is worth something, which is a good thing ;)
I removed the redundant threading because the API call is already asynchronous and does not require an additional thread to be non-blocking. After that, the callback method was being called but I ran into different problems concerning object retention. If interested you might want to check out that question, too
Thanks all.
The setDelegate method of OFFlickrAPIRequest does not retain the delegate like it should. This means you're stuck ensuring that your delegate is alive as long as the request is (or patching the class to properly own its own references).