GUI Update Synch Issues - objective-c

I am writing a program that displays to a console-like UITextView different events generated by my AudioSession and AudioQueues. For instance, when I detect that my audio route has changed, I just want a quickie message displayed on the screen on my iPhone that this happened. Unfortunately, I believe I am getting into some race condition nastiness, and I'm not sure what the best solution to solve this is.
When I run my program, my debug console spits this out:
bool _WebTryThreadLock(bool), 0x1349a0: 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...
This happens on a line of code:
textView.text = string;
I tried this:
[textView performSelectorOnMainThread:#selector(setText:) withObject:string waitForDone:YES];
And this seemed to have fixed it, but I'm pretty sure I shouldn't be doing something like this to get it to work. Unfortunately, this doesn't work with [UITextView scrollVisibleWithRange:] since this takes an NSRange, which isn't a descendant of NSObject. I think what I am doing is fundamentally wrong.
This code is called from an interruption listener, which runs from the audio queue's thread. Is there something that I should be doing that will make my updates to my textview blocking so I'm not getting this problem?
Thanks.

You are allowed to do anything about the view only from main thread, you did the right thing.
If it requires more parameters or primitive you may need a proxy function.
This is how I make a proxy function
// the caller should be like this
UTMainThreadOperationTextViewScroll *opr = [[UTMainThreadOperationTextViewScroll alloc] init];
opr.textView = textView;
opr.range = NSMakeRange(5, 10);
[UTMainThread performOperationInMainThread:opr];
[opr release];
// the Utility classes goes below
#interface UTMainThreadOperation : NSObject
- (void)executeOperation;
#end
#implementation UTMainThread
+ (void)performOperationInMainThread:(UTMainThreadOperation *)operaion
{
[operaion performSelectorOnMainThread:#selector(executeOperation) withObject:nil waitUntilDone:NO];
}
#end
#implementation UTMainThreadOperationTextViewScroll
#synthesize textView;
#synthesize range;
- (void)dealloc { /* I'm too lazy to post it here */ }
- (void)executeOperation
{
[textView scrollVisibleWithRange:range];
}
#end
PS. some declarations omitted

Related

completionHandler definition inside handleEventsForBackgroundURLSession:

This is not a trivial question asked here in StackOverFlow before, at least I haven’t found anything similar, of course I also googled it and read most of high ranked results.
BTW, if any folks here don't feel comfortable with Objective C’s block syntax, visit this page please
http://fuckingblocksyntax.com ,
before throwing any block related issues.
1st part of my question is: the background of declaration of block-parameter, as well as invoking a method which has a block-parameter ( in many cases, a completionBlock )
The “calleE-method" in MyWorker class:
… ...
#implementation MyWorker
-(void) aWorkerMethodNeedsABlockInput: ((void)(^)( NSObject *, double )) blockParam
{
NSObject *anObj=[[ NSObject alloc] init];
double *aDouble;
[self retrieveTimeConsumingResults: anObj withNumberOfTry: aDouble ];
blockParam ( anObj, * aDouble );
}
#end
The “calleR-method" in MyManager class:
#interface myManager()
#property (nonatomic) MyWorker * mWorker;
#property (nonatomic, copy) (void)(^mBlockProperty)( NSObject *, double );
#end
#implementation MyManager
-(void) aManagerMethodWhoCallsWorkerWithCompletionHandler
{
(void)(^ valBlock )( NSObject *, double ) = ^(void)( NSObject * realObj, double realDouble )
{
[realObj performSelector:#SEL( aSelector) withObject: #(realDouble) afterDelay: aTimeInterval];
} ;
self.mBlockProperty=[valBlock copy];
[self.mWorker aWorkerMethodNeedsABlockInput : self.mBlockProperty];
}
#end
above sudo-code was the NORMAL way, in our custom code, of storing a block inside property, declaring a block parameter and also offering block’s arguments in CALLEE; providing block definition and also “consuming” block’s arguments in the CALLER. I keep 'void' returnType in writing for clarity of block-syntax. Correct my writing if I did wrong, please!
2nd part of my question:
the routine usage of
- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler {
NSLog(#"Handle events for background url session");
self.backgroundSessionCompletionHandler = completionHandler;
}
then later
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session {
WebAppDelegate *appDelegate = (WebAppDelegate *)[[UIApplication sharedApplication] delegate];
if (appDelegate.backgroundSessionCompletionHandler) {
void (^completionHandler)() = appDelegate.backgroundSessionCompletionHandler;
appDelegate.backgroundSessionCompletionHandler = nil;
completionHandler();
}
NSLog(#"All tasks are finished");
}
the background callback via the daemon works in above pattern based on NSURLSession framework, right? I did it many times, not a problem on applying such pattern.
Which I have been wondering for a long time is:
What is really inside the definition of the completionHandler parameter of “handleEventsForBackgroundURLSession:” method, when the method is invoked from a block-property storage? < at the time when “ completionHandler();” is executed >
I have never seen any sample/demo which put/copy any block-of-code into completionHandler... or I wish to know too much?
What is really inside the definition of the completionHandler parameter of “handleEventsForBackgroundURLSession:” method, when the method is invoked from a block-property storage? < at the time when “ completionHandler();” is executed > I have never seen any sample/demo which put/copy any block-of-code into completionHandler... or I wish to know too much?
If I understand your question correctly, you are asking what implementation is inside the block that is passed to an application's implementation of the UIApplicationDelegate method application:handleEventsForBackgroundURLSession:completionHandler: by the system.
application:handleEventsForBackgroundURLSession:completionHandler: is invoked (indirectly) by an external service process. When an application uses NSURLSession to create a background session, that session is managed by that system service. That service does the actual background transfer and notifies UIKit/Foundation and in turn your application through a mechanism called XPC. XPC is widely used by MacOS developers, but at this time is not directly available to iOS applications - however many of the APIs and services used by developers on iOS are actually communicating with XPC services.
In the case of application:handleEventsForBackgroundURLSession:completionHandler:, the block passed to the completionHandler parameter is an opaque callback. The background transfer service needs to know when your application is done handling events for the session. Invoking that block informs the service that the application has completely processing of this set of events and the daemon can move on.
The block is created and owned by the system and as such an application should not attempt to modify or change it (other than copying the block, which is the right thing to do!). Applications should also not provide their own completion blocks - a developer-provided block would have no way to inform the transfer service of completion unless it wrapped the block passed to completionHandler: itself.
The background transfer service and NSURLSession were introduced in iOS 7. If you are writing a third party framework or library it can be very beneficial to take advantage of the service, but the framework must provide a way to handle events for any background session it owns. Perhaps because of this only a few third party libraries seem to support background transfers. Supporting this is not difficult to do - the library only needs a method to indicate ownership of the session, and a method to take the completion block and handle the events:
- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler {
if ([someCloudFrameworkObject canHandleEventsForSessionWithIdentifier:identifier]){
[someCloudFrameworkObject handleEventsForBackroundSessionWithIdentifier:identifier completionHandler:completionHandler];
}
}

main() not called in non concurrent NSOperation

When creating an NSOperation and putting it into an NSOperationQueue, I never see main() being called. Only start() is getting called. I'm not doing anything fancy, really. As a simple test, I wrote this:
NSOperationQueue *testOperationQueue = [[NSOperationQueue alloc] init];
MyTestOperation *testOperation = [[MyTestOperation alloc] init];
[testOperationQueue addOperation:testOperation];
in MyTestOperation.m:
- (void)main
{
NSLog(#"testing if main is getting called");
}
- (void)start
{
NSLog(#"testing if start is getting called");
}
MyTestOperation.h looks like this:
#import <Foundation/Foundation.h>
#interface MyTestOperation : NSOperation
#end
Am I missing something obvious?
[Edit Note: I actually meant non concurrent, not concurrent (as written in the previous title).]
I played around with your code and noticed that if I commented out your start method entirely, the main method would run. After reading the documentation for start more closely, I found this line:
The default implementation of this method updates the execution state of the operation and calls the receiver’s main method.
Thus, by overriding start with an implementation that didn't call main, you effectively short-circuited the operation and never allowed it to actually begin working! Therefore, you either need to explicitly call main within your start method, or you need to eliminate start all-together if you're not actually using it to do setup/update execution state/etc.

Why is locationManager:didUpdateHeading: not able to update this global?

I want to store the continuously updated values returned by the locationManager:didUpdateHeading: method in either a global int or a property int, so that other functions of the MotionHandler class can use it. However, this delegate method doesn't seem to be able to store its values globally but only locally. Why is that? Is it because it's not an actual MotionHandler method? How can I work around this problem? Thank you for your help.
MotionHandler.m
#import "MotionHandler.h"
#interface MotionHandler()
{
CLLocationManager *locationManager;
int degrees; // the global in question..
}
#end
#implementation MotionHandler
-(void) startCompassUpdates
{
locationManager =[[CLLocationManager alloc] init];
locationManager.delegate=self;
[locationManager startUpdatingHeading];
}
-(void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{
// This is working, a new value is stored in "degrees" & logged on the console after each update. However it only seems to be updating "degrees" locally..
degrees = (int)locationManager.heading.magneticHeading;
NSLog(#"from delegate method: %i", degrees);
}
-(int) showDegrees
{
return degrees; // This is not working. Whenever I call this method, "degrees" is always zero. Why isn't this global being updated by the previous method ?
}
TheViewController.m
//...
- (void)viewDidLoad
{
[super viewDidLoad];
currentMotionHandler = [[MotionHandler alloc] init];
[currentMotionHandler startCompassUpdates];
while(1==1)
{
NSLog(#"from showDegrees method: %i",[currentMotionHandler showDegrees]); // this just keeps returning zero..
}
}
//...
As per OP request, I have transferred my comments to an answer:
You need to stop using while loop to get constant feedback of the changing value. As Cocoa Touch is an event-based system you can't hijack its run loop by creating an infinite loop in this way. Even outside of an event-based system, using such a tight loop would hurt performance and give little gain.
If you want continuous update (or something that appears to be continuous) you can:
Use a timer to call a method every X milliseconds (see Apple Guide).
Use a background thread (see Apple Guide).
I would prefer to use the timer approach as that has the lowest overhead and runs the method in the same thread as the rest of the UI, avoiding any possible threading issue.

ios stop 2 threads from using a method at the same time

We had a bug, and it destroys the looks of our UI, some of the UI elements overlap, or has been added to the subview twice. the bug is hardly reproduced so its hard to fix it. Now I thought of the reason, and probably the method that changes the UI are being called twice at the same time. And I was correct, I tried to create the bug programatically.
We have a bug which is caused by a method being accessed by different threads at the same time. To emulate this problem, and better understand it. see codes posted below.
When I do this, updatePresence Method call, my program works perfectly
ViewController.m
-(void)loadConversationScreen{
[conversationController updatePresence];
}
But when I do this, something goes wrong with my program
ViewController.m
-(void)loadConversationScreen{
[conversationController performSelectorInBackground:#selector(updatePresence) withObject:nil];
[conversationController updatePresence];
}
This is because the method is being accessed at the same time and and the instance of my UIView is being accessed/changed also at the same time.
How do I PROPERLY stop 2 threads from using a method at the same time?
How do I properly handle it in IOS(if there is no proper way, what are the work arounds), are there built in locks or somekind?
My app should support ios 4.0 and up
Advance thanks to all for your help.
The best thread lock for you is #sycnhronized(object) {}. This means only one thread can enter the code at a time. The object passed in is used to perform the lock; only one thread can enter a block protected by a particular object's synchronized at a time. The others will wait. This can be any Objective-C object, even a NSString.
Typically, you'd use whatever object you're trying to protect from multiple threads. You probably want #synchronized(self) {}:
-(void)updateVariables {
#synchronized(self) {
_foo = 1;
_bar = 2;
}
}
#sycnhronized is re-entrant in the sense that the same thread can call #sycnhronized as deeply as it wants, for instance:
- (void)a {
#synchronized(self) {
// entered "immediately" if called from b, where the #synchronized has
// already been called
_foo = _foo + 1;
}
}
- (void)b {
#synchronized(self) {
[self a];
}
}
For posterity and because I already typed it before reading your clarification, if you really cared only about updating the UI, you'd want to force your call over to the main thread instead like this:
- (void)someTask {
dispatch_async( dispatch_get_main_queue(), ^{
[self updateUI];
});
}
- (void)updateUI {
NSAssert( [NSThread isMainThread], #"called from non-main thread" );
// do UI updates here
}
As warrenm said you shouldn't update your UIView from a different thread than the Main thread (UI thread). Still, you asked if there is any workaround for what's going on. To be honest, you should try to, instead of blocking the access of the second thread to your method, understand why the methods is called twice. This is more a logical problem than anything else and you should try to fix that, instead of trying a shortcut.

Why can't my singleton class return a value that will stay in scope

Stick with me. I'm visually impaired, have never used this site before, and will probably not post this in precisely the format that you are all used to. I apologize for any unintentional faux pas's herein.
Using Objective-C in an iOS project…
I have a singleton class, set up in what appears to be the usual way for Objective-C. It is, in the main, a series of methods which accept NSString values, interprets them, and return something else. In the code below, I'm simplifying things to the barest minimum, to emphasize the problem I am having.
From the singleton class:
- (NSUInteger) assignControlState:(NSString *)state {
// excerpted for clarity...
return UIControlStateNormal; // an example of what might be returned
}
Now, an instance of another class tries to use this method like so:
- (void) buttonSetup:(UIButton*)button {
[button setTitle:#"something" forState:[[SingletonClass accessToInstance] assignControlState:#"normal"]];
}
This code actually works. HOwever, when the system goes to draw the UI which includes the button whose title was set in this way, an EXC_BAD_ACCESS error occurs.
If the assignControlState method is moved into the same class as the buttonSetup method, no error is generated.
I'm guessing this is something about Apple's memory management that I'm not fully understanding, and how things go in and out of scope, but for the life of me, I can't figure out where I'm going wrong.
HOpe someone can help. Thanks.
The problem is in your accessToInstance method. I'll bet you are under-retaining. The implementation should be more like this:
static SingletonClass *sSingletonClass = nil;
#implementation
+ (id)accessToInstance {
if (sSingletonClass == nil) {
sSingletonClass = [[[self class] alloc] init];
}
return sSingletonClass;
}
#end
Now, if your program is following normal memory management rules, the singleton will stay around. You can check by writing:
- (void)dealloc {
[super dealloc]; // <-- set a breakpoint here.
}
If the debugger ever stops at this breakpoint, you know something in your program has over-released the singleton.
You know that bit you excerpted for clarity? I think you need to show us what it is because there's probably an over release in it somewhere.
Specifically, I think you release an autoreleased object. If you do that and don't use the object again, everything will carry on normally until the autorelease pool gets drained. The autorelease pool gets drained automatically at the end of the event at about the same time as the drawing normally occurs.
That would also explain the delayed crash following the NSLogs.