Threads from GCD reading old value - iphone

My problem is that I'm using dispatch_async(dispatch_get_main_queue(), ^(void) { ... }); to call a method asynchronously, in this method depending on some conditions i set a boolean to YES. When this boolean is read in this method, it's always read by it's old value which is NO.
The weird thing is that when i made a breakpoint on the line where the bool is checked, everything went fine and as intended !
EDIT:
Here is the code where the threads are spawned
dispatch_async(dispatch_get_main_queue(), ^(void) {
[self drawFaceBoxesForFeatures:features forVideoBox:claporientation:curDeviceOrientation image:img];
});
The method itself
- (void)drawFaceBoxesForFeatures:(NSArray *)features forVideoBox:(CGRect)clap orientation: (UIDeviceOrientation)orientation image:(UIImage *)image;
{
if (![self getSendingRequestStatus]) {
NSLog(#"Sending req");
// send async request
dispatch_async(dispatch_get_main_queue(),^ {
sendingRequest = YES;
} );
}
}

It looks like you are modifying an ivar that was created outside of a block inside of the block. In order to do this and have the ivar hold the correct value, you are going to need to use the __block keyword like so:
#interface MyCoolClass : NSObject {
#private
__block int sendingRequest_;
}
As Jack Lawrence said in the commend above, "[the runtime] takes a snapshot of all of the relevant objects/variables at that point in time". The __block identifier will tell the runtime that it should not copy that ivar to the heap and will allow you to assign values to sendingRequest_ inside of a block, even if that block is simply being run on the main thread.
A lot of good information to start with (including the above) can be found in the Blocks Programming Guide.

When primitives are passed into a block they are copied. So if you put a primitive local or instance variable in a block and then later change it either in the same method that created the block (after the block creation) or another method it won't have any effect on the variable in the block. In the case of a local variable, just make sure you make any necessary changes before block creation. In the case of instance variables you could try accessing the instance variable by using some C: self->iVar or declare it as a property and access it through the property accessor: self.iVar.

Related

Objective-C passing a block into a block

This is a bit of a tricky scenario. I've been studying blocks and started implementing them for the first time, and I found myself wanting to create a "compound block". Here's my code, roughly:
- (void)moveToPosition:(NSInteger)pos withVelocity:(CGFloat)vel onCompletion:(void(^)(BOOL completed))completionBlock
{
void (^compoundBlock) (BOOL completed) = ^(BOOL completed) {
[self unlockInteractionFromPullDownMenuTab];
void(^innerCompletionBlock)(BOOL completed) = completionBlock;
innerCompletionBlock(completed);
};
// Animate
[UIView animateWithDuration: duration
animations: ^void{ [self.pullDownMenu setFrame:newFrame]; }
completion: compoundBlock
];
}
The goal is to take a block of code that is passed into this method, add something to it, and then pass it into an animation method call. However, I get a bad access on the line:
innerCompletionBlock(completed);
I figure that my innerCompletionBlock is getting deallocated, but I'm not entirely sure why. From what I understand, blocks copy everything that you throw at them, including references to self--which can create retain cycles, and which I recently learned to avoid.
Actually, I originally tried this:
void (^compoundBlock) (BOOL completed) = ^(BOOL completed) {
[self unlockInteractionFromPullDownMenuTab];
completionBlock(completed);
};
But I was getting the bad access, and I figured that perhaps the compoundBlock wasn't copying the completionBlock, so I explicitly declared a (block) variable inside the block and assigned it to try to get it to retain (perhaps a bit silly, but I'm running under ARC so I can't do manual retain calls).
Anyway, clearly the compoundBlock is being retained when it's passed to UIView, but I'm unsure how to retain my onCompletion/innerCompletionBlock within the compoundBlock since I'm running under ARC.
Thanks in advance :)
Aha, figured it out. Bit stupid, really.
There are various times where I was calling the method - (void)moveToPosition:... and passing nil to the completionBlock parameter...because I just didn't need to do anything extra at the end of the animation and only wanted the [self unlockInteractionFromPullDownMenuTab]; that was tacked on in the compoundBlock.
Makes sense, right?
...Only if you check for nil before you call the block. As discussed elsewhere on SO, "When you execute a block, it's important to test first if the block is nil". Well, I learned my lesson there.
This code works:
// Compound completion block
void (^compoundBlock) (BOOL completed) = ^(BOOL completed) {
[self unlockInteractionFromPullDownMenuTab];
if (completionBlock != nil) {
completionBlock(completed);
}
};
Blocks are created on the stack. You need to copy completionBlock to the heap so you can be sure it will still be valid when you try to run it. Just put this at the top of your method:
completionBlock = [completionBlock copy];
Note that if completionBlock is already on the heap, this just returns the same heap copy.

Creating the loop using GCD

So here is what I've got:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1*NSEC_PER_SEC), dispatch_get_current_queue(), ^{
bool ready = some_function();
if( ready ) {
do_smth_here()
} else {
//invoke this block one more time after 0.1 sec
}
});
The problem is how can I get the reference to the current block?
Instead of jumping through the hoops shown above, I typically declare an instance method that I can call that, internally, takes care of the retriggers as necessary. That way, any given block is one-shot, but the re-trigger creates a new block.
As long as the block creation isn't terribly expensive -- which it won't be if the state is coming from whatever encapsulates the instance method -- it is efficient enough and a heck of a lot simpler.
- (void) retriggerMethod
{
... do stuff here, assuming you want to do it on first invocation ...
dispatch_after( ..., ^{
[self retriggerMethod];
});
}
You can restructure it as needed. And you can easily add a BOOL instance variable if you want to protect against simultaneous retriggers, etc...
This also provides a convenient hook for canceling; just add a BOOL to the instance that indicates whether the next invocation should really do anything and re-schedule.
Jeffrey Thomas's answer is close, but under ARC, it leaks the block, and without ARC, it crashes.
Without ARC, a __block variable doesn't retain what it references. Blocks are created on the stack. So the callback variable points to a block on the stack. When you pass callback to dispatch_after the first time (outside of the block), dispatch_after successfully makes a copy of the block on the heap. But when that copy is invoked, and passes callback to dispatch_after again, callback is a dangling pointer (to the now-destroyed block on the stack), and dispatch_after will (usually) crash.
With ARC, a __block variable of block type (like callback) automatically copies the block to the heap. So you don't get the crash. But with ARC, a __block variable retains the object (or block) it references. This results in a retain cycle: the block references itself. Xcode will show you a warning on the recursive dispatch_after call: “Capturing 'callback' strongly in this block is likely to lead to a retain cycle”.
To fix these problems, you can copy the block explicitly (to move it from the stack to the heap under MRC) and set callback to nil (under ARC) or release it (under MRC) to prevent leaking it:
__block void (^callback)() = [^{
if(stop_) {
NSLog(#"all done");
#if __has_feature(objc_arc)
callback = nil; // break retain cycle
#else
[callback release];
#endif
} else {
NSLog(#"still going");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1*NSEC_PER_SEC), dispatch_get_current_queue(), callback);
}
} copy];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1*NSEC_PER_SEC), dispatch_get_current_queue(), callback);
Obviously you can drop the #if and just use the branch appropriate for your memory management.
I think this is the code your looking for:
__block void (^callback)();
callback = ^{
bool ready = some_function();
if( ready ) {
do_smth_here()
} else {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1*NSEC_PER_SEC), dispatch_get_current_queue(), callback);
}
};
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1*NSEC_PER_SEC), dispatch_get_current_queue(), callback);
Thanks to ^ Blocks Tips & Tricks

Calling a method in Objective-C that references another class file

I am trying to call a method that checks whether the player is bigger or smaller than the enemy. (this is a fish game)
In EnemyFish.m I am using this method
-(void) compareSize:(Player*)player{
if (self.fSize > player.pSize){
isBigger = true;
}
else{
isBigger = false;
}
}
Then I want to call this method during the update so I am doing this:
-(void) update {
[self compareSize];
//Check to see if bigger than player fish
if( isBigger == true){
//code for if bigger
}else{ //etc. }
I am getting an exception: sharedlibrary apply-load-rules all
not sure what the best way to set up this method would be, and the best way to call it, since [self compareSize] is definately not working.
Any help would be greatly appreciated, Thanks!
------UPDATE----------
What about if I use this
update:(Player *)player{
The problem I was running into here, is how to call this correctly, I wasn't sure how to change this to correctly call the new update method:
[self schedule:#selector(update) interval:1.0f/60.0f];
It is unclear what you are asking, but let's look at your code and see if it helps.
Your first method can be written more concisely as:
- (void) compareSize:(Player *)player
{
isBigger = self.fSize > player.pSize;
}
There is no point in using an if/else to assign a true/false (or YES/NO) value.
Looking at this method raises the obvious question of whether it would be better returning a value rather than assigning to an instance variable. This would look like:
- (BOOL) compareSize:(Player *)player
{
return self.fSize > player.pSize;
}
and now you can use a call to compareSize in an if.
Assuming the second version of compareSize your second method is:
-(void) update
{
//Check to see if bigger than player fish
if ([self compareSize]) // OOPS, no Player
{
//code for if bigger
}
else
{
//etc.
}
}
But this doesn't work as you need an instance of Player to pass to compareSize:, e.g. [self compareSize:somePlayerInstance]. So you now have to ask yourself where you expect the Player to be found; it could be an argument to update (e.g. - (void) update:(Player *)somePlayerInstance), or you might have a method to call which returns a whole collection of players and you need to test against each one, etc., etc. I can't give an answer as I've no idea of your game and algorithm!
Following comment
You must store a reference to your Player object somewhere in your application. If there is only a single player is Player designed as a singleton with a sharedInstance, or similarly named, class method that returns the single instance? If so then your update will contain:
if ([self compareSize:[Player sharedInstance]])
etc.
Another design pattern is to have your application delegate store the reference and to provide a method (or property) for accessing it. Following this pattern (and making up a class MyDelegateApp and property player names) your code might look like:
if ([self compareSize:((MyAppDelegate *)[NSApp delegate]).player])
Yet another model is to create the single player in the application's main XIB/NIB file - etc., etc., there are many application models!
You "simply" (its not simple of course) need to design your application model so that your single player is accessible, one way or another, where you need it...
Your compareSize: method (note the colon) requires a player parameter.
So you need to call it like this:
[someEnemyFish compareSize:somePlayer]
If self is the instance of EnemyFish you want, you can do [self compareSize:somePlayer], but your title seems to indicate self isn't an EnemyFish?

iPhone block scope confusion about accessing object references

Most of the documented examples of block usage demonstrate closure with simple variables, but I've been confounded by any attempts to access objects which are present in the surrounding code. For example, this crashes in an ugly, unhelpful way:
#interface VisualizerPreset : EyeCandyPreset {
float changeSourceRate;
float (^frontPanelSlider2DisplayValueBlock)(void);
}
....
VisualizerPreset *it;
it = [[VisualizerPreset alloc] init];
it.changeSourceRate = 0.4;
it.frontPanelSlider2DisplayValueBlock = ^(void) {
return it.changeSourceRate;
};
....
// this crashes
NSLog(#"%f",it.frontPanelSlider2DisplayValueBlock());
One possible reason is that you've lost the block. A block is created in stack, not in the heap. So if you want to keep the block, you have to copy it; this will make a copy of the block in the heap.
float (^aVar) = [^{return 0.0;} copy];
Of course, you will have to also release it later.
Be careful who owns the copy of the block. Inside a block, all referenced objects are automatically retained. So it is easy to create a reference cycle. You can use __block modifier for this problem. Consider reading this http://thirdcog.eu/pwcblocks/

Initialize Objective-C string constants from plist

I have defined a constants class within my iphone program using the 'extern' and 'const' keywords as in the example described in:
Constants in Objective-C
At this point, I am trying to initialize some string constants from the contents of a plist file, instead of being defined right in the class, e.g., instead of having:
// Constants.m
NSString * const MyConstant = #"a constant";
I would like to have it initialized somewhere from the plist file. So far, I have done a test using the static +(void)load method, but I am not completely happy about it, e.g.:
// Constants.m
NSString * ALERT_QUIT_TITLE;
#implementation Constants
+ (void)load {
// this controller contains all the strings retrieved from the plist file
LabelsController *labels = [LabelsController instance];
ALERT_QUIT_TITLE = labels.alertQuitTitle;
}
#end
Using a log call I can verify that the load code gets called early in the app startup, even before the AppDelegate constructor. However, two things I see not good in this approach:
I have to remove the 'const' keyword, otherwise I get a compile error since I am trying to initialize a variable that is defined as constant
I get some sort of warning message about the autoreleased pool:
*** _NSAutoreleaseNoPool(): Object 0x50b330 of class NSPathStore2 autoreleased with no pool in place - just leaking
Stack: (0x905caf0f 0x904d8647 0x904e039f (etc)
I guess I could use a direct call to the Labels controller to retrieve the label, but I would like more to treat it like a constant having all the maint. advantages it provides.
Which would be the correct (recommended) way to initialize a constant from an external source, like in this case a plist? Hope you can help, I have lost a good few hours trying to resolve this!
Thank you in advance.
If you initialize from a plist file, then you do not have a constant. And you should not define it as such.
I am guessing what you want is to be able to treat this value as if it was a constant? And that can be achieved using lazy initialization instead.
NSString* AlertQuitTitle()
{
static NSString* title = nil;
if (title == nil)
{
LabelsController* labels = [LabelsController instance];
title = labels.alertQuitTitle;
}
return title;
}
Is there a good reason as to why you do not use the NSLocalizedString() macro to fetch the alert quit title?
The warning
As the warning states, you are executing the +load method outside of an auto release pool. Meaning that all calls to autorelease just leak memory. You can fix your method like this:
+ (void)load
{
// this controller contains all the strings retrieved from the plist file
NSAutoreleasePool* pool = [NSAutoreleasePool new];
LabelsController *labels = [LabelsController instance];
ALERT_QUIT_TITLE = labels.alertQuitTitle;
[pool release];
}
I would suggest using the NSUserDefaults method instead for storing data.
Load is called far too early in the process for most purposes. Even initialize is fairly early. As you've noted, there is no autorelease pool setup, so any use of it (which is quite hard to avoid) will give you warnings and possible leaks.
A better way to do it is to forget the constant entirely, and write LabelController alertQuitTitle to lazily initialize its database and cache its answer. Something like this (untested, uncompiled).
+ (NSDictionary*) labelStrings;
{
static NSDictionary* strings = nil;
if ( !strings ) {
// Allocate and laod and keep ownership of the NSDictionary
}
return strings;
}
+ (NSString*) alertQuitTitle
{
static NSString* alertQuitTitle = nil;
if ( !alertQuitTitle ) {
alertQuitTitle = [[LabelController strings] objectForKey:#"alertQuitTitle"];
}
return alertQuitTitle;
}
If you really want, you can convert alertQuitTitle into a macro and use that to easily create dozens of methods.
In your other code, if you really want to, you can write a method that caches the answer as well, but thats fairly pointless, instead just use [LabelController alertQuitTitle].
You can, if you prefer, use a singleton, but there is not much point even creating a single instance of LabelController unless you have other things for it to do - any data it needs can be stored as static variables. A singleton would be more inline with typical Cocoa behaviour though. Either way, the same technique will work.
To directly answer your question, it looks like you're calling load before an NSAutoreleasePool has been set up. Every thread needs its own NSAutoreleasePool; your main thread's NSAutoreleasePool is set up in main.m, which you can see if you open up that source file.
I usually initialize my application's globals in my App Delegate's init method.
But this looks like unnecessary optimization, and it's creating problems as a result. You should consider using string resources for something like this. See NSBundle localizedStringForKey:value:table:, and NSLocalizedString()