using an NSString in its customized setter causes infinite threads - objective-c

Firstly, I wrote my customized setter for an NSString* like this:
- (void)setDateString:(NSString *)newDateString {
self.dateString = newDateString;
NSInteger dateNumber = [dateString integerValue];
// this line causes crash
// do something here..blah blah
}
then the program stops due to infinitely many threads which does [XXX setDateString:].
After several useless tries I found this question/answer which tells me
do not use self. inside of custom accessors. access the variable directly,
so I made my code into
- (void)setDateString:(NSString *)newDateString {
//self.dateString = newDateString;
dateString = newDateString;
NSInteger dateNumber = [dateString integerValue];
// do something here..blah blah
}
then everything works like a charm!!
I am a junior developer of some objective languages, and a newbie to Objective-C.
I want to learn in details for this issue, instead of solving problems without understanding the reason.
So please provide me with some materials/website to understand more about this.
BTW, I use ARC.
Thank you all. :)

self.dateString = newDateString;
is equivalent to
[self setDateString:newDateString];
so this will cause infinite recursion because you are calling it inside -setDateString:.
See also Difference between self.ivar and ivar?.

The problem isn't actually this line:
NSInteger dateNumber = [dateString integerValue];
It is this line:
self.dateString = newDateString;
You see, that equals sign is akin to literally calling [self setDateString:newDateString] (in fact, that is what the compiler reinterprets it as) which creates an infinite loop. Naturally, commenting out that line would never have created that loop in the first place.

What happend is that you kept calling the function again and again causing a calling functions to fall in stak over flow
Whats wrong is int this line
self.dateString = newDateString;
This line is a objective c property, it has a getter and setters method, these method are automatically generated when you #synthesize it
the setter and getters method for dateString are:
- (void)setDateString:(NSString *)newDateString;
and
- (NSString*)dateString;
So when you call self.dateString = newDateString;
This line will call this function again
- (void)setDateString:(NSString *)newDateString {
And this function again contains the self.dateString = newDateString;, your call stack will get deeper and deeper till you are out of stack storage

Related

ObjectiveC and JavaScriptCore: Will using this method of calling CallBacks cause memory issues?

DISCLAIMER: This is a long post, but could prove very valuable for those grappling with using the new ObjectiveC JavascriptCore framework and doing asynchronous coding between ObjC and JS.
Hi there, I'm super new to Objective C and am integrating a javascript communication library into my iOS app.
Anyway, I've been trying my hand at using the new ObjectiveC JavaScriptCore Framework introduced in iOS7. It's pretty awesome for the most part, though quite poorly documented so far.
It's really strange mixing language conventions, but also kind of liberating in some ways.
I should add that I am of course using ARC, so that helps a lot coming from the Javascript world. But I have a question that's pretty specific around memory use issues when moving between ObjectiveC and the JSContext callBacks. Like if I execute a function in Javascript that then does some asynchronous code, and then calls back to a defined ObjectiveC block, and then that calls a defined JS callback... I just want to make sure I'm doing it right (ie. not leaking memory some place)!
Just to do things proper (because I reference a the class self to call the ObjectiveC callBacks I create a weakSelf so it plays nice with ARC (referenced from question: capturing self strongly in this block is likely to lead to a retain cycle):
__unsafe_unretained typeof(self) weakSelf = self;
Now, say I have a JSContext and add a function to it. I want this function to take a callBack function and call it with "Hello" as an argument as well as pass ANOTHER function as a callBack. ie.
// Add a new JSContext.
JSContext context = [[JSContext alloc] initWithVirtualMachine:[[JSVirtualMachine alloc] init]];
// Add a function to the context. This function takes a callBack function and calls it back with "Hello"
[context evaluateScript: #"var functionA = function(callBack){
var aMessage = "Foo";
callBack(aMessage, function(message){
/* message should say: Foo Bar */
});
}" ];
// Note, if you try to copy this code, you will have to get rid of the returns in the JS script.
Okay, so we have our basic JS side of things. Now to add the ObjectiveC complexity. I'm going to add the first ObjectiveC CallBack block:
context[#"functionB"] = ^(NSString *theMessage, JSValue *theCallBack){
[weakSelf objCFunction:theMessage withCallBack:theCallBack];
};
In the same class all this is happening in I also have the method definition. This is the place that causes the most concern to me:
-(void)objCFunction:(NSString *)message withCallBack:(JSValue *)callBack
{
NSString *concatenatedString = [NSString stringWithFormat:#"%#%#", message, #"Bar"];
[callBack callWithArguments:#[concatenatedString]];
}
So when I call:
[context evaluateScript: #"functionA(functionB);" ];
It should pass through the chain, and it does exactly what I expect it to do.
My main concern is that I hope I'm not somehow capturing a JSValue somewhere along this chain that is then leaking out.
Any help in helping me understand how ARC/the JSMachine would manage this approach to calling callBacks fluidly between Objective C and Javascript, would be super valuable!
Also, I hope this question helps others out there who are experimenting with this framework.
Thanks!
The problem with retain cycles occurs when you have two objects, each of which retains part of another. It's not specific to JavascriptCore. It's not even specific to blocks although blocks make the problem much easier to blunder into.
E.g.
#interface ObjcClass : NSObject
#property (strong,nonatomic) JSValue *badProp;
- (void) makeEvilRetainWithContext:(JSContext *) context;
#end
- (void) makeEvilRetainWithContext:(JSContext *) context{
context[#"aFunc"]=^(JSValue *jsValue){
self.badProp=jsValue;
};
}
The self.context[#"aFunc"] now retains the ObjcClass object because self.badProp is now inside the function obj inside the context created by assigning the block to #"aFunc". Likewise, the context is retained because one of its own strongly retained values is retained in self.badProp.
Really, the best way to avoid all this is just to not try and store JSValue in objective-c objects ever. There really doesn't seem to be a need to do so e.g.
#property (strong,nonatomic) NSString *goodProp;
- (void) makeGoodFunc:(JSContext *) context;
#end
- (void) makeGoodFunc:(JSContext *) context{
context[#"aFunc"]=^(JSValue *jsValue){
self.goodProp=[JSValue toString];
};
}
You code isn't a problem because simply passing a JSValue (even a function) through a method won't retain it.
Another way to think of it might be: After, objCFunction:withCallBack: executes, would there be anyway for the object represented by self to access the JSValue passed as callBack? If not, then no retain cycle.
Check out the WWDC introduction "Integrating JavaScript into Native Apps" session on Apple's developer network: https://developer.apple.com/wwdc/videos/?id=615 - it contains a section on Blocks and avoiding capturing JSValue and JSContext
In your sample code above, all the JSValues are passed as arguments (the way Apple recommends) so the references only exist whilst the code is executed (no JSValue objects are captured).

Objective-C block "retain cycle" warning, don't understand why

I've seen several other questions of the same form, but I either a) can't understand the provided answers, or b) don't see how those situations are similar to mine.
I'm writing a Category on UIView to recursively evaluate all the subviews of a UIView and return an Array of subviews passing a test. I've noted where my compiler warning occurs:
-(NSArray*)subviewsPassingTest:(BOOL(^)(UIView *view, BOOL *stop))test {
__block BOOL *stop = NO;
NSArray*(^__block evaluateAndRecurse)(UIView*);
evaluateAndRecurse = ^NSArray*(UIView *view) {
NSMutableArray *myPassedChildren = [[NSMutableArray alloc] init];
for (UIView *subview in [view subviews]) {
BOOL passes = test(subview, stop);
if (passes) [myPassedChildren addObject:subview];
if (stop) return myPassedChildren;
[myPassedChildren addObjectsFromArray:evaluateAndRecurse(subview)];
// ^^^^ Compiler warning here ^^^^^
// "Capturing 'evaluateAndRecurse' strongly in this block
// is likely to lead to a retrain cycle"
}
return myPassedChildren;
};
return evaluateAndRecurse(self);
}
Also, I get a bad_access failure when I don't include the __block modifier in my block's declaration (^__block evaluateAndRecurse). If someone could explain why that is, that would be very helpful too. Thanks!
The problem here is that your block evaluteAndRecurse() captures itself, which means that, if it's ever to be copied (I don't believe it will in your case, but in slightly less-trivial cases it may), then it will retain itself and therefore live forever, as there is nothing to break the retain cycle.
Edit: Ramy Al Zuhouri made a good point, using __unsafe_unretained on the only reference to the block is dangerous. As long as the block remains on the stack, this will work, but if the block needs to be copied (e.g. it needs to escape to a parent scope), then the __unsafe_unretained will cause it to be deallocated. The following paragraph has been updated with the recommended approach:
What you probably want to do here is use a separate variable marked with __unsafe_unretained that also contains the block, and capture that separate variable. This will prevent it from retaining itself. You could use __weak, but since you know that the block must be alive if it's being called, there's no need to bother with the (very slight) overhead of a weak reference. This will make your code look like
NSArray*(^__block __unsafe_unretained capturedEvaluteAndRecurse)(UIView*);
NSArray*(^evaluateAndRecurse)(UIView*) = ^NSArray*(UIView *view) {
...
[myPassedChildren addObjectsFromArray:capturedEvaluateAndRecurse(subview)];
};
capturedEvaluateAndRecurse = evaluteAndRecurse;
Alternatively, you could capture a pointer to the block, which will have the same effect but allow you to grab the pointer before the block instantiation instead of after. This is a personal preference. It also allows you to omit the __block:
NSArray*(^evaluateAndRecurse)(UIView*);
NSArray*(^*evaluteAndRecursePtr)(UIView*) = &evaluateAndRecurse;
evaluateAndRecurse = ^NSArray*(UIView*) {
...
[myPassedChildren addObjectsFromArray:(*evaluateAndRecursePtr)(subview)];
};
As for needing the __block, that's a separate issue. If you don't have __block, then the block instance will actually capture the previous value of the variable. Remember, when a block is created, any captured variables that aren't marked with __block are actually stored as a const copy of their state at the point where the block is instantiated. And since the block is created before it's assigned to the variable, that means it's capturing the state of the capturedEvaluteAndRecurse variable before the assignment, which is going to be nil (under ARC; otherwise, it would be garbage memory).
In essence, you can think of a given block instance as actually being an instance of a hidden class that has an ivar for each captured variable. So with your code, the compiler would basically treat it as something like:
// Note: this isn't an accurate portrayal of what actually happens
PrivateBlockSubclass *block = ^NSArray*(UIView *view){ ... };
block->stop = stop;
block->evaluteAndRecurse = evaluateAndRecurse;
evaluteAndRecurse = block;
Hopefully this makes it clear why it captures the previous value of evaluateAndRecurse instead of the current value.
I've done something similar, but in a different way to cut down on time allocating new arrays, and haven't had any problems. You could try adapting your method to look something like this:
- (void)addSubviewsOfKindOfClass:(id)classObject toArray:(NSMutableArray *)array {
if ([self isKindOfClass:classObject]) {
[array addObject:self];
}
NSArray *subviews = [self subviews];
for (NSView *view in subviews) {
[view addSubviewsOfKindOfClass:classObject toArray:array];
}
}

calling super from within a GCD dispatch_async block: is it safe?

I'm in a bit of a pickle. I know that calling [self methodName] from within a block will lead to a retain cycle.
However in this class due to multithreading I cannot allow execution of the method that the block is accessing from anywhere else other than the block, as it would potentially lead to serious problems.
Current code:
if (_getRunning==NO){
__weak SyncArrayMT *_weak_self = self;
_get_t = ^void (void){
_weak_self->_getRunning = YES;
NSArray *objects = [_weak_self get:getQuery
usingClassCtor:ctor
withAuthBlock:authBlock];
if (_weak_self.getBlockCb)
_weak_self.getBlockCb(objects);
_weak_self->_getRunning = NO;
};
}
Does exactly that, it calls [self getmethod]. While its ok for the dispatched block to run this method, I do not want anything outside this class calling this method.
So, would it be ok to override this inherited method as such:
- (NSArray *) get:(NSString *)getQuery usingClassCtor:(initBlock)initCb withAuthBlock:(authenticate)authBlock
{
NSLog(#"Direct call to get is not allowed - use the threaded method");
return nil;
}
And then change the block to this:
_get_t = ^void (void){
_weak_self->_getRunning = YES;
NSArray *objects = [super get:getQuery
usingClassCtor:ctor
withAuthBlock:authBlock];
if (_weak_self.getBlockCb)
_weak_self.getBlockCb(objects);
_weak_self->_getRunning = NO;
};
I have tried it and it works without doing a call to the [self getMethod], but will super be retained, properly released, etc? Yes I am using ARC. Would calling super within a block lead to any problem ? Is there a hack to get a __weak to super instead ?
Alternatively, how can I disallow direct calls to [self getMethod] (which is inherited) and only use it internally ?
I know that Objective-C doesn't exactly implement this, but I know there are tricks, such as declaring and implementing a method in the implementation file only.
EDIT#1:
I have tried with SEL & IMP and function pointers. Problem is that IMP and function pointers require as a parameter an instance, and this renders the hole point mute:
NSString * (*getFuncPtr)(id,SEL,id,id) = (NSString * (*)(id,SEL,id,id))[super methodForSelector:#selector(sendObjectsPassingTest:withAuthBlock:)];
NSString *reply = getFuncPtr(_weak_self,#selector(sendObjectsPassingTest:withAuthBlock:),predicate,authBlock);
This simply calls the inherited method. Trying to use it with super simply gives an error. At this point I will go ahead and simply use super within the block, and try and profile to see if it leads to any retain cycle.
EDIT#2:
Based on newacct's answer, this is what I ended up doing:
typedef NSArray * (* getFuncPtr)(id,SEL,id,id,id);
...
...
__weak SyncArrayMT *_weak_self = self;
_getMethod = (NSArray * (*)(id,SEL,id,id,id))[[[self class] superclass] instanceMethodForSelector:#selector(get:usingClassCtor:withAuthBlock:)];
_get_t = ^void (void){
NSArray *objects = _weak_self->_getMethod(_weak_self,#selector(get:usingClassCtor:withAuthBlock:),getQuery,ctor,authBlock);
}
I am hoping this should avoid any retain cycles, although I haven't actually profiled it yet.
I know that calling [self methodName] from within a block will lead to
a retain cycle.
That is not true in general. The block will retain self, yes. But there will only be a "retain cycle" if self somehow retains the block. In this case, it does.
but will super be retained
Yes, self will be retained (super is a call on self with a different method lookup pathway).
I have tried with SEL & IMP and function pointers. Problem is that IMP
and function pointers require as a parameter an instance, and this
renders the hole point mute:
NSString * (*getFuncPtr)(id,SEL,id,id) = (NSString * (*)(id,SEL,id,id))[super methodForSelector:#selector(sendObjectsPassingTest:withAuthBlock:)];
NSString *reply = getFuncPtr(_weak_self,#selector(sendObjectsPassingTest:withAuthBlock:),predicate,authBlock);
This simply calls the inherited method. Trying to use it with super simply gives an error. At this point I will go ahead and simply use super within the block, and try and profile to see if it leads to any retain cycle.
There are many wrong points here. First, as said above, super is a call on self (there is no such thing as a super object), so it would be sufficient to get the IMP for the method in the superclass, and call it on self.
BUT, [super methodForSelector:... does not get the method in the superclass. It actually gets the method in this class. The super in [super methodForSelector:... affects which methodForSelector: method is called. However, no class ever overrides methodForSelector:, so there is actually no difference between [super methodForSelector:... and [self methodForSelector:.... As said above, super calls the method on self, so it still finds the method based on the class of the current object.
You can get the right IMP by using the class method +instanceMethodForSelector::
NSString *(*getFuncPtr)(id,SEL,id,id) = (NSString * (*)(id,SEL,id,id))[[[self class] superclass] instanceMethodForSelector:#selector(sendObjectsPassingTest:withAuthBlock:)];
However, using the above will not work correctly if the current object is an instance of a subclass, because then [self class] will be the subclass. So to make sure it does what we want, we need to hard-code the name of our current class, or the superclass:
NSString *(*getFuncPtr)(id,SEL,id,id) = (NSString * (*)(id,SEL,id,id))[[SyncArrayMT superclass] instanceMethodForSelector:#selector(sendObjectsPassingTest:withAuthBlock:)];
NSString *reply = getFuncPtr(_weak_self,#selector(sendObjectsPassingTest:withAuthBlock:),predicate,authBlock);
It is also possible to do it using objc_msgSendSuper directly, but that function is not really that easy to use either. So I think you should stick with the IMP approach above.

If I want to make a new instance of an object in a function whose pointer is passed by reference in it

- (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. =)

iPhone simulator app crashes when appending a string

I'm a complete novice, so I'm probably missing something really easy, but I can't get my string appending to work. I add the 3rd character to typedDigit & it crashes - the method is called fine and typedDigit will get to 2 characters long. I think everything is declared properly in the header file. Code is -
-(IBAction)digitPressed:(UIButton *)sender {
NSString *digit = [[sender titleLabel] text]; // in this case, "0" - "9"
if (userIsInMiddleOfTyping) { // typedDigit is already at least 1 character long
typedDigit = [typedDigit stringByAppendingString:digit];
} else { // first character of typedDigit
typedDigit = digit;
userIsInMiddleOfTyping = YES;
}
}
Many thanks for any help!
Without the stack trace of the crash, it's hard to know the cause, but my guess will be that typedDigit is being autoreleased before the next call of your digitPressed function. stringByAppendingString: returns an autoreleased object, so you'll need to retain it if you want it to hand around past the next autorelease pool flush. For a direct fix, try something like...
if (userIsInMiddleOfTyping) {
typedDigit = [[[typedDigit autorelease] stringByAppendingString:digit] retain];
} else {
typedDigit = [digit retain];
...
More than this, you'll need to make sure you release typedDigit at some point after the typing is over, and you're finished with it.
You'll want to make sure digit is not NULL when trying to appending it. Also there is no mention of typedDigit's initialization, so if it is a garbage pointer or otherwise poorly-initialized, you'll crash when you try to manipulate it.
I think you probably have an ownership problem. If typeDigit is an object instance variable, you should be setting it with a setter method. In any case, you never call "retain" on the strings you want to keep around, so they are probably deallocated behind your back between method calls.