Objective C NSThread and anonymous function - iphone

Trying to use NSThread::detachNewThreadSelector with anonymous function
void (^testA)(void) = ^
{
NSAutoreleasePool *oPool = [[NSAutoreleasePool alloc] init];
NSLog(#"in threadA",nil);
[oPool release];
};
[NSThread detachNewThreadSelector:#selector(testA) toTarget:testA withObject:nil];
when I'm trying to run application I got error:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSThread initWithTarget:selector:object:]: target does not implement selector (*** -[__NSGlobalBlock__ testA])'
can anyone give me a hand with that?

To use that NSThread API, you mist have an object and a selector. While a block is technically an object, it doesn't have any methods that you can invoke. As such, there's nothing you could pass in the action parameter that would make this work.
If you want to execute a block asynchronously, there are a couple ways you can do it:
Use Grand Central Dispatch's dispatch_async() function, or one of the appropriate variants.
Give the block to an NSBlockOperation, and hand that off to an NSOperationQueue.
Create a method on an object that takes a block parameter and simply executes it, and then pass that object and selector, along with the block, to the NSThread API. Don't forget to -copy the block first, or you'll probably crash.

It just does not work that way. A selector is the name of a method, and a block is not a method so you can't use a selector to call a block. If you want to execute a block in the background, you can use NSBlockOperation or dispatch_async().

Related

Method calling via performSelectorOnMainThread Vs Normal method calling

can any one tell me what is different when I call method using performSelectorOnMainThread and calling same method without performSelector.
For Exa.
-(void)sampleCALL{
..........
}
NOW Call this method using these two senario:
[[self performSelectorOnMainThread:#selector(sampleCALL) withObject:nil waitUntilDone:NO];];
or
[self sampleCALL];
How these two method are getting executed?
Please help me to find this concept properly.
in firs one case [self sampleCALL]; your method will be called in the thread where control was at current time. it will maintain all the stack manipulation what it does for method calling from another method.
while
[[self performSelectorOnMainThread:#selector(sampleCALL) withObject:nil waitUntilDone:NO];];
calls the method in main thread whatever the controls current thread is. All UI actions are performed in main thread always.

performSelectorOnMainThread with multiple parameter

I am trying to perform this action on the main thread:
[curItem.mButton setBackgroundImage:newArt forState:UIControlStateNormal];
So I do this...
cWrapperObject* obj = [cWrapperObject alloc];
[obj setupParams :curItem.mButton :newArt];
[obj performSelectorOnMainThread:#selector(setImageForButton) withObject:nil waitUntilDone:YES];
I feel like this is bad, does anyone has any suggestions on how I could approach this differently?
Another option is GCD. You can invoke a block on the main queue which gets run serially when the run loop runs. blocks aren't limited to one object like performSelectorOnMainThread.
dispatch_async(dispatch_get_main_queue(), ^{
// code here
});
I wrote a more comprehensive comparison of performSelectorXXX and GCD here complete with samples:
GCD, Threads, Program Flow and UI Updating
Also, here's another related SO post:
GCD to perform task in main thread
If you need to pass only one parameter, you should set up "withObject:" argument in method performSelectorOnMainThread:withObject:waitUntilDone. So your method should be declared as
-(void)setImageForButton:(id)parameter
and you should invoke method on main thread with:
[obj performSelectorOnMainThread:#selector(setImageForButton:) withObject:newArt waitUntilDone:YES];
Note ':' in #selector(setImageForButton:) this means that this method will be messaged with one argument, passed in withObject:

iOS how to catch exception unrecognized selector sent to instance when target object is NULL already?

I read alot about what is the problem for exception "unrecog..." But i need something else
I have view with two buttons: Start and Delete, also i have two UILabels: oneLabel and secondLabel
So the I press button Start I start NSOperation thread started
And I give him labels (oneLabel,secondLabel) as params
to change text of labels on main loop i use
[oneLabel performSelectorOnMainThread:#selector(setText:) withObject:someString waitUntilDone:YES];
All works fine, but when i press button Delete - it's deleting secondLabel from view with method
[secondLabel removeFromSuperview]
and then
secondLabel=nil;
So, after what i get exception. I understand why it happened - because the target object for message with selector setText if not available now becaus it's nil.
And i get exception and app crashes.
How i can Catch this exception in this case?
For what i need it for? When use tableView controller with ImageView wich loads images in separate thread.
try this:
id yourObject;
if (yourObject != nil && [yourObject respondsToSelector:#selector(yourSelector)]) {
// Do your stuff here
}
This will only call your method to be executed if your objects is still available and it responds to the specifed selector.
Hope this helps, Vlad
setText: it is not an object, it should be a method in your implementation. someString is the object that is send to the setText method.
When the command
[oneLabel performSelectorOnMainThread:#selector(setText:) withObject:someString waitUntilDone:YES]; is executed, then the method setText is called.
You are seeing unrecognized selector sent to instance because the method
-(void)setText:(id)sender does not exist or you have misspelled it.
You dont need to catch the exception. You can make a method that waits for the selector to excecute and catches it when it is really available.
You need to probably remake the secondLabel if I understood correctly because you are deleting it. Do this first and the exception won't be there to catch.
This is not a problem to send a message to nil, it is legal. Unrecognised selector exception means you have wrong spelling in your method name. A common mistake is to forget the colon if the method requires a parameter. For example #selector(setText) when you meant #selector(setText:).

Perform Selector In Background and get the return string

I am trying to perform a selector which returns an NSString in the background thread, and the NSString returned will depend on the input object albumlink.
I am performing it in the background, as it takes a while to shorten the URL.
I would really appreciate if you could tell me how I could get the return string.
My code to perform that selector is:
[self performSelectorInBackground:#selector(shortenURL:) withObject:albumlink];
You can write another method in your class (let's call it -handleResponse:(NSString *)response), and then from the backgrounded process you can call:
[self performSelectorOnMainThread:#selector(handleResponse:) withObject:#"My response string" waitUntilDone:NO];
You can't get a function's return value outside of the thread it runs in. The whole point of doing something in a background thread is that it's taken out of the normal flow for the main thread, so there's no place for it to return to.. The most sensible approach is to create a block that's performed in the background (either through NSOperation or GCD directly) which updates either updates the value on the main thread — if you need to store the value afterward — or which just does whatever you were going to do with the value if it was only going to be used in one branch of code.

Terminating app due to uncaught exception 'NSInvalidArgumentException

Ok here is an interesting one... I am receiving the
warning: Characters may not respond to 'addHeroType:atX:atY:fromMobTable'
although I have the functions defined properly as far as I can see so how about another pair of eyes?
Here is the definition in Characters.h
-(void) addHeroType:(int)newMobType atX:(int)x atY:(int)y fromMobTable:(Mobdefs*)newMobTable;
Here is the function in the Characters.m
-(void) addHeroType:(int)newMobType atX:(int)x atY:(int)y fromMobTable:(Mobdefs*)newMobTable
and here is the call I am making in another class call heroFactory (Characters.h is included in heroFactory):
[Characters addHeroType:1 atX:location.x atY:location.y fromMobTable:newMobTable];
But this line causes the app to terminate due to uncaught exception - checking the debugger I see "NSObject Does Not Recognize Selector"
I am convinced that the issue is the wierdness of why I am seeing a warning that the Character class may not respond to the function call as written even though it matches identically to the definition.
Any help greatly appreciated.
-(void) addHeroType:(int)newMobType atX:(int)x atY:(int)y fromMobTable:(Mobdefs*) newMobTable
That is declared as an instance method.
[Characters addHeroType:1 atX:location.x atY:location.y fromMobTable:newMobTable];
But you are calling it on the class as a class method.
So either, declare the method as a class method
+(void) addHeroType:(int)newMobType atX:(int)x atY:(int)y fromMobTable:(Mobdefs*) newMobTable
Or call it on an instance
Characters *instance = [[[Characters alloc] init] autorelease];
[instance addHeroType:1 atX:location.x atY:location.y fromMobTable:newMobTable];
Depending on the scope your method requires, of course.