wait_fences: failed to receive reply: 10004003 error - objective-c

I've got some simple code that is running in a block (completion block). In the completion block I want to display an UIAlertView if the process in the block returns FALSE. As a best practice you are not supposed to call any UI methods in a background thread so I am using dispatch_get_main_queue to display the UIAlertView. This works okay except that I receive a wait_fences: failed to receive reply: 10004003 error message when the cancel button in the UIAlert view is pressed.
The code is below. I'm not sure how else to do this and to the best of my knowledge the code looks like it's correct and should work but obviously there is a problem with it. I was hoping that another set of eyes could help locate the issue.
__block bool theResult;
[self.mbProgressHUD showAnimated:YES whileExecutingBlock:^{
theResult = [someClass someMethodThatReturnsTRUEorFALSE];
} completionBlock:^{
[self.mbProgressHUD removeFromSuperview];
if (theResult) {
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *theAlert....
[theAlert show];
});
};
}];
Everything seems to work okay except when the OK button is selected in the UIAlert. I receive wait_fences: failed to receive reply: 100040003 error message.
Any help would be greatly appreciated.

removeFromSuperview directly affects the view hierarchy, which counts as touching the UI. You can't touch the UI from a background thread. You need to put [self.mbProgressHUD removeFromSuperview]; onto the main queue as well.

Related

Why is WKInterfaceLabel text not refreshing

The WatchApp receives data from the iPhone.
I refresh the label text with the data received, nothing happens, the UI is not refreshing.
Other threads suggested pushing it to the main thread and that seems to do nothing either.
Any thoughts most welcome.
-(void)session:(nonnull WCSession *)session didReceiveApplicationContext:(nonnull NSDictionary *)applicationContext
{
dispatch_async(dispatch_get_main_queue(), ^{
[self.lblTitleBorH setText:#"test"];
});
}
Are you using
[*your session* updateApplicationContext:*your dictionary* error:nil];
correctly?
try putting a NSLog inside your above didReceiveApplicationContext code and see if it is printing anything out.
In my case, when I tried to refresh the UI, I found that the outlet references were nil. The problem was caused by two interfaces on the storyboard, belonging to the same WKInterfaceController class.
When I assigned the second screen interface to another WKInterfaceController class it worked fine.
remember to call the UI objects from the main thread by using
dispatch_async(dispatch_get_main_queue(), ^{
...
});
or by using methods like performSelectorOnMainThread: withObject: waitUntilDone:

pushViewController Taking too much to show the view

I have a really light ViewController, it does nothing in viewDidLoad. I'm pushing this view on top of a navigationController. The method who does this action is called from inside a block. After the call to showView I added an NSLog, and that log prints in the console really fast, but the view takes a lot to load... I really don't understand what maybe happening... any idea???
ABAddressBookRequestAccessWithCompletion(addressBookRef, ^(bool granted, CFErrorRef error) {
[self showView];
NSLog(#"EXECUTED");
});
- (void) showView{
TestViewController *test = [[TestViewController alloc]init];
[self.navigationController pushViewController:test animated:NO];
}
From the docs for ABAddressBookRequestAccessWithCompletion:
The completion handler is called on an arbitrary queue. If your app uses an address book throughout the app, you are responsible for ensuring that all usage of that address book is dispatched to a single queue to ensure correct thread-safe operation.
You should make sure your UI code is called on the main thread.
ABAddressBookRequestAccessWithCompletion(addressBookRef, ^(bool granted, CFErrorRef error {
dispatch_async(dispatch_get_main_queue(), ^{
[self showView];
NSLog(#"EXECUTED");
});
});
This might not be the only problem, but according to the docs, the completion handler passed to ABAddressBookRequestAccessWithCompletion is called on an arbitrary queue. -showView should only be called on the main queue since it is dealing with UIViewController objects.
The other thing to ask is what else is happening on the main queue? Are there other long-running tasks that could be blocking UI updates?

Modal NSAlert within block not displayed

In my document-based application, I have overridden the method openDocument: in my subclass of NSDocumentcontroller so that I can display my own openPanel. I pass the chosen URLs to the method openDocumentWithContentsOfURL:display:completionHandler:. I use this code for the call:
[self openDocumentWithContentsOfURL:[chosenFiles objectAtIndex:i] display:YES completionHandler:^(NSDocument *document, BOOL documentWasAlreadyOpen, NSError *error) {
if (document == nil)
{
NSAlert* alert = [NSAlert alertWithError:error];
[alert runModal];
}
}];
So I want to display the passed error if nil gets returned as a reference to the document. The problem is, that the program just "freezes" after I press the "Open" button in the open panel. Then I need to manually stop the program with the "stop" button in Xcode. No spinning beach ball appears, though. If I comment the line "[alert runModal]", the program does not freeze any more, but no alert is displayed, of course.
Now the strange thing: The code works sometimes. If I switch from Xcode to my browser and back and I run the program again, it sometimes works flawlessly and the error is displayed. After some time it stops working again. It is unpredictable, but most of the time it doesn't work.
All this sounds like a race-condition to me. It certainly has something to do with the block? But what do I do wrong?
Converting my comment to an answer:
runModel on the main thread.
[alert performSelectorOnMainThread:#selector(runModal) withObject:nil waitUntilDone:NO];
I think runModel needs to be called on the main thread because it's part of the AppKit framework, and it's estentially triggering UI graphics. I believe all calls to the AppKit framework or to any method that manipulates graphics needs to be on the main thread.

WebView did finish launching does not work

what is wrong with this method?
- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
[activityIndicator stopAnimation:self];
}
I want to stop the Circular Progress Indicator (activityIndicator). But there is something wrong with - (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame. I am coding for mac osx and not for iOS. I heard something from Delegates, what does that mean?
Check to be sure that your UIWebView has set its delegate. Setting a delegate is basically telling the program who you want to handle events (like taps, gestures, or, in this case, the loading of a webView). Thus when an event is fired, it will inform the delegate and the delegate can process it. Maybe if you post more of your code it would help, but I would check your declaration of the UIWebView in question. Be sure that after you allocate it and initialize it, you set its delegate to self (assuming that this method is in the same class), like so:
UIWebView *myWebView = [[UIWebView alloc] init];
[myWebView setDelegate:self];
If you have not set the delegate, it is firing off events and no one is receiving them to process them. The method you are using is waiting for the specific event sent by any webView. When it is sent an event message it passes, as a parameter, the webView that triggered. In any case, put in a log statement to be sure you are entering the method. That will tell you if it is receiving the event messages.
- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
NSLog(#"Did finish loading...");
[activityIndicator stopAnimation:self];
}
NOTE: This is as per iOS experience, but should work for Mac OS as well. Let me know what your log result is, if the method is getting called or not.

NSOperationQueue and UITableView release is crashing my app

This is by far the weirdest problem I've been stuck with.
I have a UIViewController on a UINavigationController and I want to call a method at viewDidAppear using NSInvocationOperation so it can run on a back thread when the view becomes visible.
The problem is that if I pop the view controller BEFORE the operation (in this case the testMethod method) completes running, the app crashes.
Everything works fine if I pop the view controller AFTER the operation runs it's course.
When the app crashes, it stops at [super dealloc] with "EXC-BAD-ACCESS" and gives me the following error.
bool _WebTryThreadLock(bool), xxxxxxxxx: Tried to obtain the web lock
from a thread other than the main thread or the web thread. This may
be a result of calling to UIKit from a secondary thread. Crashing
now...
And this is my code (super simplified)..
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSInvocationOperation *theOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(testMethod) object:nil];
[operationQueue addOperation:theOperation];
[theOperation release];
}
- (void)testMethod
{
NSLog(#"do some stuff that takes a few seconds to complete");
}
- (void)dealloc
{
[_tableView release];
[super dealloc];
}
The testMethod has some code that takes a few seconds to complete. I only have a few clues and I really don't know how and where to start debugging this.
Clue #1: The funniest thing is that if I remove the [_tableView release]; from dealloc then the app doesn't crash. But of course this would cause a leak and I can't remove it.
Clue #2: I've tested this code on a separate "clean" UIViewController with a UITableView and to my surprise it didn't crash.
Clue #3: The app doesn't crash is the UITableView's datasource is set to nil in viewDidLoad.
Clue #4: The app doesn't seem crash if I use the same code in viewDidAppear somewhere else like an IBAction.
Clue #5: I've tried looking over stack data with NSZombie but it gives me tons of data and it leads me nowhere.
I have some very complicated code within my UITableViewDelegate and UITableViewDataSource and I really don't know where to start debugging this. I really hope I don't have to go through line by line or rewrite the entire thing because of this.
Any pointers on where I should be looking?
The problem is likely that your view controller's last reference is the operation queue holding onto it, which means you are technically calling (or having the system call) some UIKit methods in a background thread (a big no-no) when the operation cleans up.
To prevent this from happening, you need to send a keep-alive message to your controller on the main thread at the end of your operation, by adding something like this to the last line in your testMethod:
[self performSelectorOnMainThread:#selector(description) withObject:nil waitUntilDone:NO];
There is still a chance that this message may get processed before the operation queue releases your view controller, but that chance is pretty remote. If it's still happening, you could do something like this:
[self performSelectorOnMainThread:#selector(keepAlive:)
withObject:[NSNumber numberWithBool:YES]
waitUntilDone:NO];
- (void)keepAlive:(NSNumber *)fromBackground
{
if (fromBackground)
[self performSelector:#selector(keepAlive:) withObject:nil afterDelay:1];
}
By sending a message to your view controller on the main thread, it will keep the object alive (NSObject retains your view controller until the main thread handles the message). It will also keep the view controller alive if you perform a selector after a delay.
You're crashing because the controller is still trying to use your tableView reference and since you poped the viewController, everything will go away in the dealloc and the tableView is still populating itself.
You can try asking in your dealloc method if your operation is still running, so you can cancel it and the everything should be fine.
Once you add an operation to a queue, the operation is out of your
hands. The queue takes over and handles the scheduling of that task.
However, if you decide later that you do not want to execute the
operation after all—because the user pressed a cancel button in a
progress panel or quit the application, for example—you can cancel the
operation to prevent it from consuming CPU time needlessly. You do
this by calling the cancel method of the operation object itself or by
calling the cancelAllOperations method of the NSOperationQueue class.
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. The default
implementation of NSOperation does include checks for cancellation.
For example, if you cancel an operation before its start method is
called, the start method exits without starting the task.