Identify thread of current scope - iphone

How does one determine the thread a given function call is running on?
I want to make sure a method is called on the main thread in order to update some UI elements.
Can I for example do something like this?
- (void) myMethod {
if (<current thread is not main thread>) {
[self performSelectorOnMainThread: #selector(myMethod) withObject: nil waitUntilDone: NO];
} else {
// my code here
}
}

Check out [NSThread isMainThread].
http://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSThread_Class/Reference/Reference.html#//apple_ref/occ/clm/NSThread/isMainThread

Related

Block inside block = EXC_BAD_ACCESS

I have a singleton class the handle all the Game Center logic:
typedef void (^GameCenterCallbackFinishUpdating)();
- (void)getAllMatches:(GameCenterCallbackFinishUpdating)onComplete
{
[GKTurnBasedMatch loadMatchesWithCompletionHandler:^(NSArray *matches, NSError *error)
{
//Do stuff here...
onComplete();
}];
}
From another viewController I use:
[[GameCenterHelper sharedHelper] getAllMatches:^{
[self.myTableView reloadData];
}];
It works great when I'm in the app, but once I close the app (background) and then start it up again, I get:
onComplete(); ---- Thread 1: EXC_BAD_ACCESS (code=2, address=0xc)
What am I doing wrong here?
some background info: the blocks are objects and if any block is nil and you try to call them, it crashes the application.
somewhere and somehow the block onComplete becomes nil before you call it. the following if (...) statement helps you to prevent to call a nil pointer, so the application won't crash.
if (onComplete) onComplete();
Thanks to #holex and #Paul.s for explaining it well.
I had the similar situation where I was sending block as method parameter(completionHandler).
- (void)callX:(NSString *)xyz withCompletionHandler:(void (^)(NSString *response))completion
{
completion(something);
}
And there are two situations either I am using this block like:
[MyClass sharedInstance] callX:#"abc" withCompletionHandler:^(NSString *response) {
if (response) {
//do something
}
}];
or this block could be nil as method parameter:
[MyClass sharedInstance] callX:#"abc" withCompletionHandler:nil];
In second case when block was being passed nil as method parameter this caused EXC_BAD_ACCESS on completion(). So as #holex states that the blocks are objects and if any block is nil and you try to call them, it crashes the application.
A single if saves lot of my time
- (void)callX:(NSString *)xyz withCompletionHandler:(void (^)(NSString *response))completion
{
if (completion)
completion(something);
}
P.S: this explanation only for NERDS like me. | ' L ' |

Dealing with Blocks, completion handlers, dispatch_async vs dispatch_sync

I'm executing an online fetch of data in a thread and I want to do something immediately after the block is executed.
Here's my code:
- (IBAction)refresh:(UIBarButtonItem *)sender {
NSLog(#"checking");
[self editToolbar];
dispatch_queue_t fetchQ = dispatch_queue_create("Refreshing", NULL);
dispatch_async(fetchQ, ^{
[self setupFetchedResultsController];
[self fetchImonggoItemsDataIntoDocument: self.itemDatabase];
});
dispatch_release(fetchQ);
NSLog(#"done checking");
//do something here
}
The thing is dispatch_async returns immediately and "done checking" prints immediately even before the block is done executing. How do I solve this?
I think it's an architectural issue. The tasks are something like:
edit toolbar
fetchImonggoItemsDataIntoDocument
do something else
If these must be done exactly in order then I don't quite understand the use of blocks or queues; just run the statements after each other and you'll be set.
Otherwise, alternative #1 would be to use dispatch_sync rather than dispatch_async. Again, I'm not quite sure what the benefit of using a queue would be but there it is.
Alternative #2 would be to use a callback from the block. Something like:
- (IBAction)refresh:(UIBarButtonItem *)sender {
NSLog(#"checking");
[self editToolbar];
dispatch_queue_t fetchQ = dispatch_queue_create("Refreshing", NULL);
dispatch_async(fetchQ, ^{
[self setupFetchedResultsController];
[self fetchImonggoItemsDataIntoDocument: self.itemDatabase];
[self doneChecking]; // <-- NOTE! call the callback
});
dispatch_release(fetchQ);
}
// NOTE! refresh: has been split up into two methods
- (void)doneChecking:
NSLog(#"done checking");
//do something here
}
As others have already suggested, this is probably what you need.
NSArray *items = [iMonggoFetcher fetchImonggoData:IMONGGO_GENERIC_URL_FOR_PRODUCTS withFormat:#"json" withDateRangeArgs:args];
[document.managedObjectContext performBlock:^{
for (NSDictionary *itemInfo in items){
[Product productWithImonggoInfo:itemInfo inManagedObjectContext:document.managedObjectContext];
}
// Put here what you need :)
}];

UI hangs inspite calling a lengthy method in background thread

I am calling a method like methodA in background.now if i call a lengthy method called methodB from methodA.should i separately mention it to be in background.the reason i ask this question is inspite of calling the lengthy process in background thread,the ui hangs for some time.
ie
[self performSelectorInBackground:#selector(methodA)];
-(void)methodA
{
NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
[self methodB];
[pool drain];
}
-(void)methodB
{
NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
//some lengthy process
[self performSelectorOnMainThread:#selector(updateTable) withObject:nil waitUntilDone:NO];
[pool drain];
}
-(void)updateTable
{
[self.tableview reloadData];
}
is this way of calling background method right?
If a selector (method) X is called on a certain thread (whether it be background or main thread), any selectors that X calls (in the conventional fashion) are also on that same thread. So no, you don't need to call performSelectorInBackground: for each sub-call from methodA: as long as the entry-point selector is on the 'correct' thread, anything it then does is also on the 'correct' thread, including calls to other methods.
Note that the NSAutoreleasePool you set up in methodB looks unnecessary -- you don't really need it, since you're already inside the scope of the NSAutoreleasePool set up in methodA. (Assuming that methodB is only called from methodA as in the example!)
Incidently, have you put in NSLogs to absolutely verify that //some lengthy process is actually the thing taking all the time?

Make sure function runs on main thread only

How can I make sure that my function is run only on the main thread? It updates UI elements.
Is a function like this considered 'bad'?
-(void)updateSomethingOnMainThread {
if ( ![[NSThread currentThread] isEqual:[NSThread mainThread]] )
[self performSelectorOnMainThread:_cmd withObject:nil waitUntilDone:NO];
else {
// Do stuff on main thread
}
}
I wrote it like this to avoid having a second function, initially I had it like this:
-(void)updateSomethingOnMainThread_real {
// Do stuff on main thread
}
-(void)updateSomethingOnMainThread {
[self performSelectorOnMainThread:#selector(updateSomethingOnMainThread_real) withObject:nil waitUntilDone:NO];
}
As an alternative to ayoy's method-based GCD implementation for guaranteeing execution on the main thread, I use the following GCD-based function in my code (drawn from another answer of mine):
void runOnMainThreadWithoutDeadlocking(void (^block)(void))
{
if ([NSThread isMainThread])
{
block();
}
else
{
dispatch_sync(dispatch_get_main_queue(), block);
}
}
You can then use this helper function anywhere in your code:
runOnMainThreadWithoutDeadlocking(^{
// Do stuff that needs to be on the main thread
});
This guarantees that the actions taken in the enclosed block will always run on the main thread, no matter which thread calls this. It adds little code and is fairly explicit as to which code needs to be run on the main thread.
This is fine. You can also use GCD to execute code on the main thread.
Checkout this SO post.
GCD to perform task in main thread
I wrote this simple #define which I've been using with great success:
#define ensureInMainThread(); if (!NSThread.isMainThread) { [self performSelectorOnMainThread:_cmd withObject:nil waitUntilDone:NO]; return; }
That way your method, assuming it's parameterless, looks like this
- (void) updateTheThings {
ensureInMainThread();
[self.dog setTailWag:YES];
// etc...
Alternatively, you can use Grand Central Dispatch API, but it's not very handy:
-(void)updateSomethingOnMainThread {
void (^doStuff)(void) = ^{
// stuff to be done
};
// this check avoids possible deadlock resulting from
// calling dispatch_sync() on the same queue as current one
dispatch_queue_t mainQueue = dispatch_get_main_queue();
if (mainQueue == dispatch_get_current_queue()) {
// execute code in place
doStuff();
} else {
// dispatch doStuff() to main queue
dispatch_sync(mainQueue, doStuff);
}
}
otherwise, if synchronous call isn't needed, you can call dispatch_async() which is much simpler:
-(void)updateSomethingOnMainThread {
dispatch_async(dispatch_get_main_queue(), ^{
// do stuff
});
}

how to stop performing selector in background?

I have some class A. In this class i have a method,
which calls [self performSelectorInBackground:...]. And it starts downloading
some info from internet.
After i tap Home button, then enter the app again, this background method keeps working.
So, if i call this method again, i have bad_access, because background method is already working and i call it twice.
Can i stop performing selector in background of the class A? For example in my applicationDidEnterBackground?
Or can i check, if selector is performing or something?
I found couple things like
[[NSRunLoop currentRunLoop] cancelPerformSelectorsWithTarget:a];
[NSObject cancelPreviousPerformRequestsWithTarget:a selector:#selector(startDownload) object:nil];
But they didn't work for me.
So
my objAppDelegate:
#inteface ObjAppDelegate
{
A *a;
}
#implementation ObjAppDelegate
{
-(void)applicationDidEnterBackground:(UIApplication *)application
{
//or it can be didBecomeActive..
//here. check if background task of class A is running, or just stop it ??
}
}
#implementation A
{
//some timer, or event, etc.
-(void)startDownload
{
[self performSelectorInBackground:#selector(runBackgroundTask) withObject:nil];
}
-(void)runBackgroundTask
{
//some network stuff..
}
}
i did it like this:
threadForDownload = [[NSThread alloc] initWithTarget:self selector:#selector(threadMain:) object:nil];
[threadForDownload start];
[self performSelector:#selector(startDownload) onThread:threadForDownload withObject:nil waitUntilDone:NO];
(void)threadMain:(id)data {
NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSRunLoop *runloop = [NSRunLoop currentRunLoop];
[runloop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
while (YES) {
[runloop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
[pool release];
}
In my startDownload method i look at activity indicator to check, whether
startDownload is already running..
-(void)startDownload
{
if (![[UIApplication sharedApplication] isNetworkActivityIndicatorVisible]) // flag..
{
//....
}
}
// I make visible networkActivityIndicator every time i start downloading
You can easily create a BOOL instance variable to determine whether background task is active.
BOOL isBackgroundTaskRunning;
Then in runBackgroundTask
if (isBackgroundTaskRunning) {
// already running
return;
}
isBackgroundTaskRunning = TRUE;
...
isBackgroundTaskRunning = FALSE;
Here's what to do:
the background task saves its thread to a property somewhere using NSThread currentThread
the background task periodically checks the thread's isCancelled property.
the main thread sends cancel to the thread object saved by the background thread in step 1.
On exit, the background thread sets the property to nil.
All of the operations on the property used to store the thread in have to be protected by #synchronized or equivalent to prevent the main thread from sending cancel to a deallocated thread object.
The background thread can't do IO operations that block for more than a short period of time. In particular, synchronous downloading of URLs using NSURLConnection is out. If you are using NSURLConnection, you'll want to move to the asynchronous methods and a run loop (arguably, in that case, you can do away with the background thread altogether). If you are using POSIX level IO, use poll() with a timeout.
I don't think that it would be save to force the interruption of a method. What you can do is to change the state of your object and check that state inside your method implementation to early return in case of a cancel (but don't forget to release allocated objects).
This is how NSOperationQueue works. From the documentation:
Cancelling an operation does not immediately force it to stop what it is doing. Although respecting the value returned by the isCancelled is expected of all operations, your code must explicitly check the value returned by this method and abort as needed.
Run the method in a background thread, and keep a record of the NSThread. Then later, you can just end the thread.