In the debugger (gdb and llvm),
I usually do:
po self
po myIvar
p (CGPoint)whatEver
and works fine except when I am inside of a block. How can I access them in the debugger? I don't like very much writing NSLogs everywhere ...
I suppose inside blocks In the debugger I need to access ivars in a different way but I don't know how :(
Blocks are their own environment when they're executed. The neat thing about them is that they'll capture any variables from the surrounding scope that you mention in their bodies. The flip side of that is that there's no access to variables that aren't captured.
Take a look at this snippet:
NSArray * a = [NSArray array];
NSDictionary * d = [NSDictionary dictionary];
NSString * s = #"This is my string. There are many others like it.";
void (^myB)(NSInteger) = ^(NSInteger i){
NSString * lS = [s lowercaseString];
lS = [lS stringByReplacingOccurrencesOfString:#"many" withString:[NSString stringWithFormat:#"%ld", i]];
/* Breakpoint here */ NSLog(#"%#", lS);
};
myB(7);
The Block captures s and uses it. The NSInteger parameter, i, is also used and accessible inside the Block. The breakpoint gets hit when the Block is executed, though, which means that the creating scope, with the array a and dictionary d, no longer exists. You can see this if you look at the local variable display in Xcode:
Aside from globals, that's all you or the debugger have access to when the Block is executing. If you really need to know the values of other variables during that time, I think you'll have to mention them inside the Block. This will capture them, which will mean (for objects) they'll be retained and then released when the Block is deallocated.
Related
I would like to modify various variables which exist outside an Objective-C block within it's body.
I know I can directly access and modify a variable using the __block attribute while declaring the variable. So this works:
__block NSMutableString *alertMessage;
void(^appendMessage)(NSMutableString*, NSString*)= ^(NSString *append){
if (!alertMessage)
{
alertMessage = [NSMutableString new];
}
if ([append length] > 0)
{
[alertMessage appendString:#"\n"];
}
[alertMessage appendString:append];
};
appendMessage(#"Alert part 1"); //This works fine
However I want to create a block which can perform an operation on a passed variable, enabling me to use the operation on multiple variables outside the block without directly accessing the same. Something like the following:
__block NSMutableString *alertMessage;
__block NSMutableString *otherString;
void(^appendMessage)(NSMutableString*, NSString*)= ^(NSMutableString *string, NSString *append){
if (!string)
{
string = [NSMutableString new];
}
if ([append length] > 0)
{
[string appendString:#"\n"];
}
[string appendString:append];
};
//The following do not work as intended
appendMessage(alertMessage, #"Alert Part 1");
appendMessage(otherString, #"Bleh bleh");
I want to be able to use the above block to modify the variables declared before it.
How can I achieve such an operation? Is this even possible?
Your question shows some confusion over values and variables, maybe the following will help.
Modify parameters in Objective-C blocks
In (Objective-)C all parameters to methods/functions/blocks are passed by value, e.g. when in the call f(x) the value of the variable x is passed to f, not the variable itself. This is known as call-by-value.
There are languages which do allow variables to be passed, known as call-by-reference. When used the argument must be a variable and the parameter name within the function is effectively an alias to the supplied variable. This is not supported directly in (Objective-)C.
However you can emulate it in (Objective-)C. It is not commonly used, with one notable exception: many methods use it to return an NSError * value.
You later comment:
What I want to achieve includes object creation, which is essentially what the question now boils down to. "Can I create an object declared outside within a block?". The answer which I have gathered with the help of all the activity here is NO.
You can, it is just a question of whether you should (i.e. is the design right?) and the best way to do it.
The straightforward way to solve your particular issue is to write a function:
NSMutableString *alertMessage;
NSMutableString *otherString;
NSMutableString *(^appendMessage)(NSMutableString *, NSString *) =
^(NSMutableString *string, NSString *append)
{
if (!string)
string = [NSMutableString new];
if (append.length > 0)
{
[string appendString:#"\n"];
[string appendString:append];
}
return string;
};
alertMessage = appendMessage(alertMessage, #"Alert Part 1");
otherString = appendMessage(otherString, #"Bleh bleh");
If you really (really, really) want to you can instead "pass the variable" by passing its address (using the & operator) and indirection (using the * operator) inside the block to get/set the value:
void (^appendMessage)(NSMutableString **, NSString *) =
^(NSMutableString **stringPtr, NSString *append)
{
if (!stringPtr) return; // no "variable" passed
NSMutableString *string = *stringPtr; // use indirection to get the value in the passed variable
if (!string)
string = [NSMutableString new];
if (append.length > 0)
{
[string appendString:#"\n"];
[string appendString:append];
}
*stringPtr = string; // use indirection to set the passed variable
};
appendMessage(&alertMessage, #"Alert Part 1"); // pass "variable" by passing its address
appendMessage(&otherString, #"Bleh bleh");
While the above is valid code it is generally not recommended coding practice in Objective-C for simple cases such as yours.
Once you take the address of a variable you need to be concerned over the lifetime of that variable - if you attempt to use the address to access the variable after the variable has been destroyed your program will fail (the dangling pointer problem)
What about __block?
Neither of the above examples use __block anywhere.
When a block references a variable by default it captures the variables value at the time the block is created. The __block attribute changes this to capturing the variable (so its value can be changed by the block) and alters the lifetime of the capture variable if required (so the variable lives at least as long as the capturing block, avoiding the dangling pointer problem).
The __block attribute is not applicable in your situation as you wish to capture different variables based on the call.
HTH
The code, as written, seems to confuse operation on object with object creation.
For clarity's sake, you should either pass in a mutable object to be manipulated or you should define a single __block variable whose value will be set by the block (and you do the logic after to figure out where that value should be stuffed).
Passing in something by reference is inherently dangerous to the point of being an anti-pattern (what happens as soon as you try to refactor the code to be asynchronous? At least in the __block case, the code after the block will see nil).
i.e.:
__block NSMutableString *foo = [sourceString mutableCopy];
doIt(#"new stuff"); // appends to `foo`
whereItShouldReallyGo = foo;
I have been trying to understand the difference between Strong and Weak references in iOS. What I did to understand is:
//.h File
#property(nonatomic,strong) NSString* myStrongString;
#property(nonatomic,weak) NSString* myWeakString;
//.m File
- (void)viewDidLoad
{
[super viewDidLoad];
[self assignTempString];
// Do any additional setup after loading the view, typically from a nib.
}
-(void)assignTempString{
self.myStrongString = [[NSString alloc] initWithString:#"Varun Mehta"];
}
- (IBAction)printAssignedString:(id)sender {
NSLog(#"Object will have strong reference so it will print my name==%#",self.myStrongString);
}
According to my understanding when I repeat the above step by using myWeakString it should print null. But its still printing my name. Anybody having any idea why its happening.
But when I replace [[NSString alloc] initWithString:#"Varun Mehta"] with [NSString stringWithFormat:#"Varun Mehta"] or [[NSString alloc] initWithFormat:#"Varun Mehta"] result is coming as I have expected.
There are several things to consider here.
A statically declared string is built into your app so it isn't really retained or released, thus a weak reference to #"my string" will always be valid. The compiler is just recognizing [[NSString alloc] initWithString:#"Varun Mehta"] as a static string and removing your alloc/init. However anything that deals with formatting is, by definition, creating a new string and thus the new string obeys the weak referencing rules and is immediately deallocated, nil-ing out the reference.
If you access a weakly retained object that ends up in the autorelease pool it won't actually get deallocated until all your methods return and the run loop goes back into another cycle (and thus drains the autorelease pool), so you can continue to work with the object even though it is "walking dead". This is typically only when interacting with non-ARC code.
If you need practise try this code:
- (void)viewDidLoad
{
[super viewDidLoad];
[self assignTempString];
}
-(void)assignTempString{
#autoreleasepool
{
self.myStrongString = [NSString stringWithFormat:#"%#", #"Strong string"];
self.myWeakString = [NSString stringWithFormat:#"%#", #"Weak string"];
}
}
- (IBAction)printAssignedString:(id)sender {
NSLog(#"Strong ptr content: %#",self.myStrongString);
NSLog(#"Weak ptr content: %#",self.myWeakString);
}
[NSString alloc] will allocate an ARC-managed object and will set its retain count to 1. As long as your view controller is alive, this retain count will be 1, so it will not be deallocated. [NSString stringWithFormat:] returns an autoreleased string which is deallocated after the execution of [self assignTempString].
Two methods initWithString and stringWithFormat suggest exactly what is to expect.
So initWithString expects you to create allocate memory and then initialise it.
While stringWithFormat expects you to just point to the string.
When you do a init with your strong/weak variable it will exist till end of your program.
While when you point;
strong literal will keep a reference and hence will not allow ARC to cleanup the string literal,
weak literal will not keep a reference and hence ARC is free to clean it up immediately after the function call.
Hope it clarifies working for you.
What you are experiencing happens because of how NSString is implemented.
Since NSString objects are immutable the compiler takes a shortcut when you use stringWithString: with a string literal as argument. If the argument of this and other related methods is a string literal the returned value will just point to the string literal. The whole object instantiation is optimized away.
And string literals won't be deallocated. But the weak variable is only nil'd out during dealloc, so if dealloc is never called the weak variables are never set to nil.
This won't happen if you use stringWithFormat:. Even using only string literals as argument will create new string instances.
Why? Most likely because Apple decided that it's not worth the effort to check if stringWithFormat: was used with a string literal that does not have any format specifiers.
That's an implementation detail, don't think too long about this decision. It should not influence the code you write. I would suggest you treat every string that is not a bare literal (i.e. #"Foo" without any NSString methods) as dynamically created NSString (i.e. use isEqualToString: for all your string comparisons)
This logging code will show this reuse behaviour. It'll show the same addresses for all NSString instances, because the compiler has optimized all those calls to a simple #"Foo".
NSLog(#"%p", #"Foo");
NSLog(#"%p", [[NSString alloc] initWithString:#"Foo"]);
NSLog(#"%p", [NSString stringWithString:#"Foo"]);
NSLog(#"%p", [[NSString stringWithString:#"Foo"] copy]);
NSLog(#"%p", [#"Foo" copy]);
In newer versions of Xcode you will even get nice warnings for this code:
using initWithString: with a literal is redundant
using stringWithString: with a literal is redundant
I need to know if I do it correctly. The application is running OK but I'm not sure I get the lifecycle correctly (leak ?).
Note: Instrument see no leak.
The code of a method aaa: of some class A:
- (void) aaa {
NSString *path = ...something...;
NSBlockOperation* theOp = [NSBlockOperation blockOperationWithBlock: ^{
// using path
[self somethingElseWith:path];
}];
[self.aQueue addOperation:theOp];
}
So I create a block to put on aQueue (NSOperationQueue*). The goal is to offload from the main thread the long running somethingElseWith: method, so that the GUI continue to be responsive.
Inside the block I reference the local var "path" that will be out of scope at the end of the aaa: method.
If I read the doc correctly, the block will do a retain on 'path'. But is ARC inserting a release at the end of this block implicitly ? Would be logical and nice.
Or should I declare 'path' as __block and assign it to nil at the end of my block ? (manual...)
Not sure I understand how to use __weak in this context.
The path variable is fine. You may however need to avoid a retain cycle by using a weak reference to self. If aQueue is a strong reference there may be a retain cycle causing self never to be released.
Solution:
- (void) aaa {
NSString *path = ...something...;
__weak id self_ = self;
NSBlockOperation* theOp = [NSBlockOperation blockOperationWithBlock: ^{
// using path
[self_ somethingElseWith:path];
}];
[self.aQueue addOperation:theOp];
}
Make sure the operation does not get called after the class should no longer exist.
The block will automatically handle memory management for any locals from the enclosing scope. You don't have to worry about retain/release pairs in this case. Note, though that path will be const within the block's scope. If you need pathto be mutable within the block, use the __block attribute.
The different ways a block handles variables is described in detail here: Blocks and Variables
I have the following code
- (NSString *)stringByEscapingXMLEntities;
{
NSString *result;
#autoreleasepool {
result = [self stringByReplacingOccurrencesOfString:#"&" withString:#"&"];
result = [result stringByReplacingOccurrencesOfString:#"\"" withString:#"""];
// ... lot of -stringByReplacingOccurrencesOfString: calls
result = [result stringByReplacingOccurrencesOfString:#" " withString:#" "];
}
return result;
}
I ask myself now how would I transfer ownership result out of the method. Before ARC I would have retained result before exiting the autorelease block and returned it autoreleased at the end of the method.
Thanks!
There are two ways to do that:
Rename the method to something like copyStringByEscapingXMLEntities -- the copy indicates the transfer of ownership and ARC creates the code accordingly.
Append, in the header, NS_RETURNS_RETAINED to the method definition like this: - (NSString *)stringByEscapingXMLEntities NS_RETURNS_RETAINED.
EDIT: As 'iljawascoding' mentioned, the #autoreleasepool has no real need to be kept around -- except for optimization.
EDIT 2: And remember: ARC always does the right thing. All the things you tried (your comment) result in the very same correct program -- albeit with the lack of some optimization if result was defined as __strong.
Get rid of the autorelease altogether. According to Apple, ARC will automatically insert the necessary release after your code is done with the temporary instances stored in 'result'. There's nothing to gain by rolling your own autorelease pool here.
The code you have posted is correct. Any crash has a different cause.
Because result is a strong reference outside the autorelease scope, ARC is responsible for keeping it alive when exiting the pool, and it does. You don’t need to do anything special.
More specifically, ARC generates code equivalent to this:
void *_arp = objc_autoreleasePoolPush();
temp1 = objc_retainAutoreleasedReturnValue([self stringByReplacingOccurrencesOfString:#"&" withString:#"&"]);
temp2 = objc_retainAutoreleasedReturnValue([temp1 stringByReplacingOccurrencesOfString:#"\"" withString:#"""]);
objc_release(temp1);
result = objc_retainAutoreleasedReturnValue([temp2 stringByReplacingOccurrencesOfString:#" " withString:#" "]);
objc_release(temp2);
// result is not released here
objc_autoreleasePoolPop(_arp);
return objc_autoreleaseReturnValue(result); // Result is returned autoreleased, or handed off to a matching objc_retainAutoreleasedReturnValue() in the caller.
Note that the temporary variables are handled with objc_retainAutoreleasedReturnValue/objc_release pairs. Because of the runtime optimization implemented by objc_retainAutoreleasedReturnValue and objc_retainAutoreleasedReturnValue, this means that the temporary values will actually be released immediately without ever being put in an autorelease pool if -stringByReplacingOccurrencesOfString: is built with ARC. My guess would be that most of the system frameworks aren’t yet, though.
Why not use [[NSString alloc] initWithString:result] before the #autoreleasepool scope closes? But why the ARP in the first place?
- (void)createAString:(NSString **)str
{
*str = [NSString stringWithString:#"Hi all!"];
[*str autorelease]; // ???? is this right ?
}
How should I use release or autorelease ? I don't want to release outside of the function of course :)
...
NSString *createStr;
[self createAString:&createStr];
NSLog(#"%#", createStr);
You're correct that you'd generally want to return autoreleased (or the like) objects from out params when you use this form. Your assignment statement in the function that sets *str to a string:
*str = [NSString stringWithString:#"foo"];
is already doing the right thing, because that method returns an instance of NSString that the caller doesn't own. Just like you could return this string object from your function without any further memory management, you can set it as the outparam as you've done. Your second snippet showing the call site is fine.
This said, I'm worried about a few things in your code that you should be sure you understand:
The value of str inside the method is still a **, and sending that a message (as you've done for the speculative autorelease) is nonsense. Be sure you fully understand doubly indirected pointers before using them too liberally. :) If you need to send str a message after creating it, send it to *str, which is what contains the NSString *.
Setting an outparam like this when the function returns void is not idiomatic Cocoa. You would normally just return the NSString * directly. Outparams are rare in Cocoa. (Usually just NSErrors get this treatment from framework calls. Otherwise they conventionally use name like getString to differentiate them from normal get accessors which don't use the word "get".)
I hope -stringWithString was just an example. That method is almost never used in practice, since it's equivalent (in this case) to just using a #"string literal" (although that would muddy your example).
Instead of using a double pointer, would it not be more elegant to use an NSMutableString instead?
- (void)createAString:(NSMutableString *)str
{
[str setString:#"Hi all!"];
}
....
NSMutableString *createStr = [[NSMutableString alloc] init];
[self createAString: createStr];
NSLog(#"%#", createStr);
[createStr release];
Or, even better, just have the createAString method return an NSString.
- (NSString *)createAString
{
return #"Hi all!"; // this is autoreleased automatically
}
I wouldn't want to presume that your needs are this simple, though. =)