Trying to understand blocks on iOS - iphone

I am trying to understand how to use blocks on iOS. I have read Apple's docs but, as usual, they are vague and incomplete and several essential bits of information are not mentioned. I have also googled around without success. This is what I am trying to do as an exercise to understand that.
I have created a block to read a string and compare the string to the previous read. If the strings are not the same, return YES, if they are the same, return NO.
This is how I did:
I declared this on .h
BOOL (^differentStrings)(void);
I declared this on .m, inside viewDidLoad in a viewController
__block NSString * previousString;
__block NSString * currentString;
differentStrings = ^(void){
currentString = [self getString];
NSLog(#"%#", currentString); // not printing anything on console
if (![currentString isEqualToString:previousString]) {
previousString = currentString;
return YES;
} else {
return NO;
}
};
This is how I use: I have a thread that does this:
if (differentStrings)
NSLog (#"strings are different);
These are the problems I have:
the block always return YES (strings are different)
I am not comfortable declaring this inside videDidLoad. How should I declare this, so I can use it globally as a method? Should I put this like I would with a method?
I am calling a method "getString" inside the block. Is it OK?
I find strange to declare the block variables on .m. As I see, I should declare the block variables on .h and then just use them on .m. I have tried to do that, but received an error.
I have setup a debugging point on the first line of the block but it is not stopping there;
NSlog line inside the block do not prints anything. Isn't the block being called?
Can you guys help me with this?

You're misunderstanding how blocks work. (Okay, so that's kinda obvious.) In the same way that previousString is a variable pointing to an NSString, differentStrings is a variable pointing to a block. Not the result of running the block, but rather, the block itself. That is, after you do this:
__block NSString * previousString;
__block NSString * currentString;
differentStrings = ^(void){
currentString = [self getString];
NSLog(#"%#", currentString); // not printing anything on console
if (![currentString isEqualToString:previousString]) {
previousString = currentString;
return YES;
} else {
return NO;
}
};
differentStrings is a variable pointing to the block.Thus, when you do this:
if (differentStrings)
…you're simply checking whether differentStrings contains something other than 0 or NULL. Since it contains a block, it is not empty, so it evaluates to true.
Remember: differentStrings is a block variable, not a BOOL variable. It contains a block (a function, if you will), which when called will return a bool. Thus, in order to actually run the block, you need to call it. Like this:
differentStrings();
or, in your case:
if (differentStrings()) {
NSLog (#"strings are different");
}
Edit: As pointed out in the comments, since differentStrings is an instance variable, you need to copy it, just like you'd call retain on any other object assigned to an instance variable. (For technical reasons I won't go into now, you should always use copy with blocks instead of retain.) Likewise, you'll need to call release on it at some point later, perhaps in your dealloc method.

I don't believe you're actually executing the block. I think your code should be
if (differentStrings())
{
NSLog (#"strings are different);
}
Treat a block like a function. I think you were just checking to see whether the block had been defined, not executing it.
Also, if you don't need to access an NSString outside of the block, you could get rid of the __block qualifier and move the currentString declaration inside of the block.
If you need another resource on blocks, I cover them in the fall session of my advanced iOS development course on iTunes U. I describe block syntax in the Understanding Cocoa session, and their use in Grand Central Dispatch within the multithreading session. The course notes also have links to some sample applications that use blocks in different ways.
I also can't recommend highly enough that you watch the WWDC 2010 video sessions 206 - Introducing Blocks and Grand Central Dispatch on iPhone and 211 - Simplifying iPhone App Development with Grand Central Dispatch.

Related

Copied blocks and CLANG leak warnings

I have a method which takes a block:
- (void)methodWithBlock:(blockType)block
The method starts out by copying block, because it does asynchronous things before using it, and it would be discarded otherwise. It then calls the method within another block, and then releases it, within that block. Summarily:
- (void)methodWithBlock:(blockType)block
{
block = [block copy];
[something asyncStuffWithFinishedBlock:^{
// ..
block();
[block release];
}];
}
CLANG complains about memory leaks for "block". If I remove the copy and release statements the block will be gone by the time it's called -- at least earlier crashes indicates that this is the case.
Is this the wrong way to do things? If so, how should I do the above -- i.e. a block callback from within a block statement in a method? I can't store block as an instance variable, as the method could be called repeatedly with different arguments while the asynchronous part is happening.
First, the -copy and -release should be unnecessary. The -asyncStuffWithFinishedBlock: method must copy the block that's passed to it. When a block is copied and it references other block objects, it copies those block objects, too. You need to figure out the real nature of the crash you were seeing.
Second, you are releasing the wrong thing. [block copy] does not modify the block (the receiver of the -copy message) somehow turning it into a copy. It returns a copy of that block. It is this returned copy that you want to reference both in the invocation statement (block();) and when releasing.
So, you could do:
block = [block copy];
[something asyncStuffWithFinishedBlock:^{
// ..
block();
[block release];
}];
Note the reassignment of the local block variable to point to the copy.
Think of it this way: would you ever copy a string the way you attempted to copy that block? Would you do:
[someString copy];
// ... use someString ...
[someString release];
I don't think you should do the release inside the block like that. You are assuming that the block gets called exactly once. But just from the code, we don't know that. It could be that the method does not execute the block at all, in which case you won't be releasing, so leaking. It could also be the case that the method executes the block more than once, in which case you would be over-releasing.
If you really want to copy it, you need to release it outside the block like this (the scope that retains something should be responsible for releasing it):
- (void)methodWithBlock:(blockType)block
{
block = [block copy];
[something asyncStuffWithFinishedBlock:^{
// ..
block();
}];
[block release];
}
(It's irrelevant what asyncStuffWithFinishedBlock might to with its argument; according to the memory management rules, if it needs to keep it around for longer, it will need to retain or copy it (for blocks it needs to copy it).)
However, as Ken Thomas pointed out, it shouldn't be necessary for you to copy it in this method since you're not storing the block anywhere. asyncStuffWithFinishedBlock should copy its argument block if it needs to run it asynchronously; and any blocks captured by that block should be copied when it is copied.

ARC : Is this approach correct

This may sound a newbie question however I'm new to iOS dev.
I've following code in my project, the project is ARC enabled, and I get error on its execution (bad access), and would like to understand the cause of the problem and solve it.
on some button press following code is invoked in MTClassA.m file
-(void) someMethod
{
for (int i = 0; i < N; i++) {
...
(param1 and param2 are location variables)
...
mFlickr = [[MTFlickr alloc] initWithParam1:param1 param2:mparam2];
mFlickr.delegate = self;
[mFlickr fetchImages];
}
}
in MTClassA.h header file mFlickr is declared as MTFlickr* mFlickr so default it it with __strong qualifier.
the callback function of fetchImages class is following
- (void)didRecieveImageLinksFromFlickr:(NSArray*)response
param1:(NSString*)param1 param2:(NSString*)param2 {
...
}
So basically I would like to know is it correct to create mFlickr objects this way in for loop and expect the callback to work correctly, if no please suggest what need to be changed ?
P.S. Do I need to change mFlickr to local variable ? If yes how should I be guaranteed that param1 and param2 methods are the one's that I've passed for teach iteration in for loop ?
You are creating multiple instances of the mFlickr object within your loop, and presumably assigning them to the same instance variable. Under ARC an assignment to an instance variable will automatically release the previous value, so your mFlickr objects are getting destroyed as soon as they are created (except the last one).
Presumably your mFlickr object is setting itself as a delegate for a URL request, it is probably this callback which is failing since the request's delegate no longer exists.
If you are creating multiple instances you should store them in an array instance variable. The callback should include a reference to the particular instance that has returned, and at this point, you remove it from the array.
You don't need to change the mFLicker to local variable. The only thing that i found in your code wrong is that, you are immediately setting mFlicker to self after initializing it. i think you must want to set the delegate of the mFlicker that you can do it by
[mFlicker setDelegate:self]
Did you set #property for mFlicker?
.h
#property(nonatomic, retain) MTFlickr *mflicker;
.m
#synthesis mflicker;
I also had similar experience, ARC was releasing my object after initialization.
so try changing your code to
self.mFlickr = [[MTFlickr alloc] initWithParam1:param1 param2:mparam2];
mFlickr.delegate = self;
[mFlickr fetchImages];
I am also not sure but i just wanted to provide some help

Where to initialize an instance variable in a class

I'm new to objective-c and I always have problem with global variable . I don't know where to initialize them . My problem is with an NSString . I wrote this code –
in .h
NSString *session ; // i also #property(retain,nonatomic) and synthesize ...
in viewDidLoad , '
session=#"HEllo";
and in
-(IBAction) showInformations:(id)sender;
{
NSLog(#" informations ok");
NSLog(#"my sesison : %# ",session);
}
But I have a crash in show information :/ session is empty I think . Help please
session = #"hello";
self.session = #"hello";
There is a huge difference between the above two statements. The first one just assigns hello to session. Here the string hello is autoreleased, so session is not valid when you tap the button, as you have not retained session. But in 2nd line self is used. When self is used, it is not just a simple assignment, it is actually a call to accessor method. Here you have used retain in property declaration. So when self is used, the setter for session is called which retains it. So session is valid when you tap the button.
The summery is use right property and use self to avoid many memory problems.
EDIT: As pointed by fluchtpunkt, this explanation is not valid for string literals. I was out of my mind that string literals are special when writing this.
Try setting it using the dot syntax for a property:
self.session=#“Hello”;
This will ensure proper memory management.
There must be another write access to session somewhere in your code. A line of code that looks like session = [NSString stringWith...];
So find the other parts of the code where you assign something to the session variable and replace the wrong memory management over there with proper memory management. The problem is not within the three lines you have shown.
Depending on your code it should be something like
self.session = [NSString stringWith...
or if you like it inconvenient
[session release];
session = [[NSString stringWith...] retain];

About using convenient method and the time of their autorelease

This maybe too basic but I couldn't find an exact answer. I'll be happy to delete/close this post if anyone point me to similar posts.
I want to call method "getString" to return a formatted string and set to my label like this:
-(NSString*) getString {
NSString *result = [NSString stringWithFormat:#"blah blah %#", someOtherString];
return result;
}
-(void) viewDidLoad {
someLabel.text = [self getString];
}
This code worked for me, but I am concerned that result is allocated by a convenient method thus may be auto-released before it got retained by the label. Is it true? If so, when exactly would an object from convenient method get released?
Second question, if in case I have to use [NSString alloc] to create my own string object. Where and how should I release it?
Thanks in advance
Leo
It isn't true that the object will be autoreleased before you retain it. The details of when the pool gets drained are unimportant to answer this question, except that it can't happen during your code unless you call drain or release on the pool. If your function calls another function, except in some specific edge cases both the function you call and the function you called from need to exit before that thread can do anything else. The autorelease pool is thread-specific.
To answer your second question, if you alloc an object you should release it when you've finished using it. Simple as that. That includes when you pass it to other code that needs it, because it should be up to that other code to claim ownership if it needs to.
This code worked for me, but I am concerned that result is allocated by a convenient method thus may be auto-released before it got retained by the label.
Yes, it will be autoreleased because it is returned by a method whose name does not contain new, alloc or copy. No, this won't happen before the calling method viewDidLoad returns.
In fact, the autorelease-pool, to which it's added will probably be the one set-up and teared-down by the runloop, so nothing is going to happen to it until the end of the current iteration through the runloop.

Why should a self-implemented getter retain and autorelease the returned object?

Example:
- (NSString*) title {
return [[title retain] autorelease];
}
The setter actually retained it already, right? and actually nobody should bypass the Setter... so I wonder why the getter not just returns the object? It's actually retained already. Or would this just be needed in case that in the mean time another objects gets passed to the setter?
From here http://www.macosxguru.net/article.php?story=20030713184140267
- (id)getMyInstance
{
return myInstanceVar ;
}
or
- (id)getMyInstance
{
return [[myInstanceVar retain] autorelease] ;
}
What's the difference ?
The second one allows the caller to get an instance variable of a container object, dispose of the container and continue to play with the instance variable until the next release of the current autoreleased pool, without being hurt by the release of the instance variable indirectly generated by the release of its container:
aLocalVar = [aContainer getAnInstanceVar] ;
[aContainer release];
doSomething(aLocalVar);
If the "get" is implemented in the first form, you should write:
aLocalVar = [[aContainer getAnInstanceVar] retain];
[aContainer release];
doSomething(aLocalVar);
[aLovalVar release];
The first form is a little bit more efficent in term of code execution speed.
However, if you are writing frameworks to be used by others, maybe the second version should be recommanded: it makes life a little bit easier to people using your framework: they don't have to think too much about what they are doing…;)
If you choose the first style version, state it clearly in your documentation… Whatever way you will be choosing, remember that changing from version 1 to version 2 is save for client code, when going back from version 2 to version 1 will break existing client code…
It's not just for cases where someone releases the container, since in that case it's more obvious that they should retain the object themselves. Consider this code:
NSString* newValue = #"new";
NSString* oldValue = [foo someStringValue];
[foo setSomeStringValue:newValue];
// Go on to do something with oldValue
This looks reasonable, but if neither the setter nor the getter uses autorelease the "Go on to do something" part will likely crash, because oldValue has now been deallocated (assuming nobody else had retained it). You usually want to use Technique 1 or Technique 2 from Apple's accessor method examples so code like the above will work as most people will expect.
Compare this code
return [[title retain] release]; // releases immediately
with this
return [[title retain] autorelease]; // releases at end of current run loop (or if autorelease pool is drained earlier)
The second one guarantees that a client will have a non-dealloced object to work with.
This can be useful in a situation like this (client code):
NSString *thing = [obj title];
[obj setTitle:nil]; // here you could hit retainCount 0!
NSLog(#"Length %d", [thing length]); // here thing might be dealloced already!
The retain (and use of autorelease instead of release) in your title method prevents this code from blowing up. The autoreleased object will not have its release method called until AFTER the current call stack is done executing (end of the current run loop). This gives all client code in the call stack a chance to use this object without worrying about it getting dealloc'ed.
The Important Thing To Remember: This ain't Java, Ruby or PHP. Just because you have a reference to an object in yer [sic] variable does NOT ensure that you won't get it dealloc'ed from under you. You have to retain it, but then you'd have to remember to release it. Autorelease lets you avoid this. You should always use autorelease unless you're dealing with properties or loops with many iterations (and probably not even then unless a problem occurs).
I haven't seen this pattern before, but it seems fairly pointless to me. I guess the intent is to keep the returned value safe if the client code calls "release" on the parent object. It doesn't really hurt anything, but I doubt that situation comes up all that often in well-designed libraries.
Ah, ok. from the documentation smorgan linked to, it seems this is now one of the methods that Apple is currently recommending that people use. I think I still prefer the old-school version:
- (NSString *) value
{
return myValue;
}
- (void) setValue: (NSString *) newValue
{
if (newValue != myValue)
{
[myValue autorelease]; // actually, I nearly always use 'release' here
myValue = [newValue retain];
}
}