Objective-C self->_ivar access with explicit vs implicit self-> - objective-c

General Problem
Until now, I always thought self->_ivar is equivalent to _ivar. Today I found out that this is not entirely true.
See, for example the following code snippet:
#interface TestClass : NSObject {
NSString *_testIVar;
}
#end
#implementation TestClass
- (instancetype)init
{
if ((self = [super init])) {
_testIVar = #"Testing Only";
}
return self;
}
- (void)test
{
{
NSInteger self = 42;
NSLog(#"without arrow: %#", _testIVar); /* OK */
NSLog(#"with arrow: %#", self->_testIVar); /* COMPILER ERROR! */
}
}
#end
Even though I hid the original self with some NSInteger also named self, the implicit ivar syntax _testIVar still finds the "original" self whereas self->_testIVar obviously does not. In the latter case the compiler correctly complains with
Member reference type 'NSInteger' (aka 'long') is not a pointer
In the first case however, it just works.
The Real-world Problem
This example might seem rather artificial but it's not at all. For example the ExtObjC project (used by ReactiveCocoa ) defines the very handy #weakify(var) and #strongify(var) which help against strongly capturing self (and other objects) in blocks by defining a really handy syntax (no need to write the odd and cumbersome to write __weak typeof(self) weakSelf = self; [...] ^{ __strong typeof(self) strongSelf = weakSelf; [...] } anymore). For example:
- (void)someMethod
{
#weakify(self);
dispatch_async(self.someQueue, ^{
#strongify(self);
NSLog(#"self # %p", self);
}
}
Without #weakify and #strongify, the block would capture a strong reference to self. With the #weakify and #strongify it doesn't. So the deallocation of self would not be postponed until the block has been run. The main advantage though is that you don't need to remember to use weakSelf or strongSelf instead of self because the "original" self is hidden.
That's very handy, the ExtObjC implements #weakify / #strongify by generating something similar like the following with macros:
- (void)someMethod
{
__weak typeof(self) _weakSelf = self;
dispatch_async(self.someQueue, ^{
__strong typeof(self) self = _weakSelf;
NSLog(#"self # %p", self);
}
}
Fair enough, that's even better because we can just continue to use self without actually capturing a strong reference to self. However, as soon as we use the implicit-ivars-of-self-syntax, a strong reference to the "original" self will still be captured!
- (void)someMethod
{
#weakify(self);
dispatch_async(self.someQueue, ^{
#strongify(self); /* compiler warning: Unused variable self here!!! */
NSLog(#"self->_testIVar: %#", _testIVar);
}
}
Misc
When using ivars in blocks, we're definitely capturing self. See for example this screenshot:
.
Another fun thing about the screenshot is that the warning messages are
Unused variable 'self'
and in the line below
Capturing 'self' strongly in this block is likely to lead to a retain cycle
That's why I think there are two versions of self :-)
Question
The actual question here is: What exactly does _testIVar mean? How does it find the "original" self pointer?
To clarify (also see my screenshot): As #MartinR pointed out (which is what I think as well), there is some special version of self which cannot be changed and is only used for implicit-self-ivar-access. Is that documented somewhere? Basically where is defined what the implicit self refers to? It seems to behave the same way that for example Java does (with this) but with the difference that this is a reserved keyword that you cannot override.
The question is also not how to "fix" it, just writing self->_testIVar will be what I want in the #weakify/#strongify example. It's more that I thought by using #weakify/#strongify you cannot make the mistake of implicitly strongly capturing self anymore but that simply does not seem to be the case.

All Objective-C methods are called with two hidden arguments (from the "Objective-C Runtime Programming Guide"):
The receiving object
The selector for the method
and a method can refer to the receiving object as self (and to its own selector as _cmd).
Now _ivar is equivalent to self->_ivar where self is this implicit first
function parameter.
As long as you don't define a new variable self in an inner scope, _ivar == self->_ivar holds true.
If you define a new variable self in an inner scope then you have
The locally defined self,
the "implicit self" which is the first function parameter,
and _ivar still refers to the "implicit self"! This explains the compiler warnings in your block, which seem to contradict each other:
"Unused variable 'self'" refers to the locally defined self,
"Capturing 'self' strong in this block ..." refers to the "implicit self" of the function.
The following code demonstrates also this:
#interface MyClass : NSObject
{
NSString *_ivar;
}
#end
#implementation MyClass
- (void)test
{
_ivar = #"foo"; // Set instance variable of receiver
{
MyClass *self = [MyClass new]; // Redefine self in inner scope
self->_ivar = #"bar"; // Set instance variable of redefined self
NSLog(#"%# - %#", self->_ivar, _ivar);
// Output: bar - foo
}
}
#end

Related

In Objective-C++, for testing, how can I make a class nil at runtime?

Here's the situation:
In async functions, I capture a weakSelf.
__block auto weakSelf = self;
Then, inside the block, I capture a strongSelf of that weakSelf.
[_someIvar someAsyncMethod:^{
__strong auto strongSelf = weakSelf;
}];
But, if strongSelf is nil, I do some error handling and reporting.
if (!strongSelf) {
_NotifyDelegate(someDeallocationError); // C
}
The whole thing:
__block auto weakSelf = self;
[_someIvar someAsyncMethod:^{
__strong auto strongSelf = weakSelf;
if (!strongSelf) {
// How can I trigger this line?
_NotifyDelegate(someDeallocationError); // C
}
}
}];
This is all legacy code, and I'm adding unit tests using OCMock. How can I make strongSelf nil at runtime and trigger that delegate notification?
You haven't specified any class names as far as I can see, but assuming you have:
#interface SomeClass
…
#end
…
#interface IvarClass
- (void) someAsyncMethod:(void(^)(void))block;
#end
…
#implementation SomeClass
{
IvarClass* _someIvar;
}
…
- (void)someMethod
{
__block auto weakSelf = self;
[_someIvar someAsyncMethod:^{
__strong auto strongSelf = weakSelf;
if (!strongSelf) {
// How can I trigger this line?
_NotifyDelegate(someDeallocationError); // C
}
}];
}
#end
In that case, I would subclass IvarClass with a StubIvarClassDelayedAsync where you override - (void) someAsyncMethod: so that the block is simply stored in an ivar. You then implement another method on it along the lines of - (void)completeAsyncMethod which calls the block.
You will need to use an instance of this StubIvarClassDelayedAsync as your _someIvar in your test - either you can inject this directly via the existing API on SomeClass, otherwise you may may need to subclass SomeClass to change wherever the production instance is created.
Putting it all together in the test method: Within an #autoreleasepool block, create an instance of your SomeClass (or its stub subclass), prepare it with an instance of StubIvarClassDelayedAsync, then call someMethod. This in turn should cause your overridden version of someAsyncMethod: to be called, which stores the block reference. (You can assert that the method was called for good measure.) nil out the SomeClass pointer in your test and close the pool block to remove any last references. You may want to assert that dealloc is called on your SomeClass instance, which you can easily do if using a dummy subclass. Make sure to retain a pointer to your StubIvarClassDelayedAsync instance however. Finally, call completeAsyncMethod on that stub instance, which should cause the block to take the error handling branch.
I'd be more specific about a code example if you provided a little more than just unnamed fragments, if you've got code preceding or following these fragments within the respective methods, then that may need to be taken into account or refactored first. Real names would also be useful.

memory/pointer behavior for self = [super init]

Forgiveness, please: I am a beginner. I was looking at another quesiton/answer and came across this code:
SpinningView *spinner = [[SpinningView alloc] initWithFrame:CGRectMake(0.0, 0.0, 20.0, 20.0)]
// Now let's take a look at the implementation of SpinningView's -initWithFrame: method
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
self.backgroundColor = [UIColor clearColor];
}
return self;
}
I believe that, in the second section of code, self points to the instance to which the message was sent that resulted in "self" being encountered, i.e., the result of [SpinningView alloc]. (Or doesn't that produce an instance?)
So, when you call self = [super initWithFrame:frame] on the 4th line of code, are you not reassigning the pointer value associated with "spinner"? I.e, are you not abandoning the memory you allocated in the first line? Or does the compiler someone know just to copy memory values instead of changing the pointer value? Or... what??
Thanks!
This is the standard idiom for the -init method of obj-c objects. The idea being that, whatever was allocated from +alloc doesn't matter, only what was returned from -init matters. Now, -init will usually just use the already-allocated object that's in self. But it's not required to. It is free to deallocate that object and create a new one. The classic example is when you alloc/init an NSString* you don't actually get back an instance of NSString*, you get back a concrete subclass. This is because NSString* is a "class cluster". So when you call +alloc you get back an NSString*, but when you call -init it frees that object and reallocates an object of one of its subclasses, initializes that new object, and hands it back to you.
Another example would be if you had a class that tried to memoize itself. Lets say you have an immutable class that gets initialized with a number. You could change your -init to re-use existing instances of the class. Here's an example (note: not thread-safe):
static NSDictionary *numberCache;
#interface MyNumber : NSObject
#property (readonly) int number;
- (id)initWithInt:(int)i;
#end
#implementation MyNumber
+ (void)initialize {
if (self == [MyNumber class]) {
numberCache = [[NSDictionary alloc] init];
}
}
- (id)initWithInt:(int)i {
// find ourself in the numberCache
NSValue *val = [numberCache objectForKey:#(i)];
if (val) {
// yep, we exist. Release the just-allocated object
[self release];
// and retain the memoized object and stuff it back in self
self = [[val nonretainedObjectValue] retain];
} else if ((self = [super init])) {
// nope, doesn't exist yet. Initialize ourself
_number = i;
// and stuff us into the cache
val = [NSValue valueWithNonretainedObject:self];
[numberCache setObject:val forKey:#(i)];
}
return self;
}
- (void)dealloc {
// remove us from the cache
[numberCache removeObjectForKey:#(_number)];
[super dealloc];
}
#end
#KevinBallard covered most of the points. The reason we need the self = is because init is not guaranteed to return the same object it is called on (it could return a different object or nil). I will answer your questions and expand on the memory management aspects:
I believe that, in the second section of code, self points to the
instance to which the message was sent that resulted in "self" being
encountered, i.e., the result of [SpinningView alloc].
Yes
So, when you call self = [super initWithFrame:frame] on the 4th line
of code, are you not reassigning the pointer value associated with
"spinner"?
Yes. Not spinner (spinner doesn't exist at this point anyway). You are re-assigning the pointer variableself inside the method.
I.e, are you not abandoning the memory you allocated in the first
line? Or does the compiler someone know just to copy memory values
instead of changing the pointer value? Or... what??
Yes. Under MRC, you are just re-assigning the pointer, and the compiler does not do anything except change the pointer value. Under ARC, it's more complicated, but at the end of the day, the compiler just does the same as under MRC in this case, i.e. just re-assigns the pointer.
It's not really "abandoning" the memory if you think about it. You see, by convention, init methods take ownership of ("consume") an already-retained object that they're called on (usually the return result of a call to alloc), and they return a retained object. But these two don't have to be the same object. So when your init method is called, its self is already retained, and the init method owns it, but then it calls [super init...], which calls the superclass's init method on self, so that method now takes ownership of the self which your init had ownership to. And in return, that superclass's init returns back to you a retained instance, which you assign to self. You did not "abandon" self because you gave it to the superclass's init method, which in turn became responsible for memory managing it (including releasing it if it wants to return something else).

Block that can access self and be used throughout an instance

I want a block that is available throughout a class, so it can be re-used many times by different methods in the instance.
I want that block to be able to reference self.
I want to not have the block create any nasty retain cycles by retaining self.
So far I am stumped. I managed to create block in the .m outside of any method definitions, and that got me partway - I could reuse the block everywhere, but I couldn't access self. I tried putting the block into an ivar but I'm doing something wrong there and now I'm getting random EXC_BAD_ACCESS. Can someone explain it simply, line by line?
Try the following:
typedef void (^MyBlock)();
#implementation MyClass
{
MyBlock block;
}
- (id) init
{
self = [super init];
if (!self)
return nil;
__block MyClass* _self = self;
block = [^ {
[_self sendSomeMsg];
} copy];
}
Note the __block storage type. Quoting this: "At function level are __block variables. These are mutable within the block (and the enclosing scope) and are preserved if any referencing block is copied to the heap."
This idiom may help you to remove the exc_bad_access (ARC code).
// get a weak reference to self
__weak id weakSelf = self;
block = ^()
{
// now the block is executing so we get a strong reference to self
// (this prevents self from disappearing until the block is done executing)
id strongSelf = weakSelf;
if (strongSelf != nil)
{
// do whatever work you intended for this block
}
};
I figured it out.
In MyClass.h:
typedef void (^DefaultFailureBlock)();
#property (copy) DefaultFailureBlock defaultFailureBlock;
in the init method:
__block MyClass *selfReq = self;
self.defaultFailureBlock = ^{
//use selfReq instead of self in here.
};
Interestingly, if you accidentally refer to self inside the block, you will have a retain cycle, and Analyze will not complain. I put an NSLog in dealloc to prove that it is actually being dealloced, and it is.
Oh and don't forget to [defaultFailureBlock release]; in dealloc too...

Super in initializing objects [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
why does initializing subclasses require calling the super class's same init function?
I really can't understand the role of super in initializing an object.
For example, having this (example — not written by me) code:
#implementation MyObject
- (id) init
{
if([super init]){
return self;
} else {
return nil;
}
}
#end
What [super init] actually does? I'm confused, can't get the point
It is necessary to ensure correct initialisation of inherited instance variables from the super class of MyObject.
Since Objective-C is object oriented you can inherit from other classes. When you inherit from other classes you can intercept messages and get to decide if you pass them on to the class you inherit from. In the case of init it is almost always important to do self = [super init] or use the designated init method of the class to make sure the object is created correctly. Imagine if in MyObject in your init method you create an NSMutableArray that your class uses but init was never called because someone else inherited from your class and never called [super init]. You would then have nil references or either a bad pointer every where you attempted to used your NSMutableArray. The reason why it is important to set self equal to [super init] is the value of self may change such as in error recovery.
//this is valid
-(id)init
{
if((self = [super init]))
{
if(someInitializationFails)
{
[self release];
self = nil;
}
}
return self;
}
Wil Shipley recommends this (from 2009):
- (id)init;
{
if (!(self = [super init]))
return nil;
// other stuff
return self;
}
But why assign super init's return to self?
Matt Gallagher's article attempts to explain it...
-- Quote:
If you remember back at the start, I
said that the initWithString: part of
a typical [[MyClass alloc]
initWithString:#"someString"]
invocation is converted into an
objc_msgSend call:
MyClass *myObject2 = objc_msgSend(myObject1, initSelector, #"someString");
So by the time we get
to the inside of the method, self
already has a value; its value is
myObject1 (i.e. the allocated object,
as returned from the [MyClass alloc]
call. This is essential because
without it, the super invocation
wouldn't be possible — the self value
is used by the compiler to send the
invocation:
[super init];
becomes:
objc_msgSendSuper(self, #selector(init));
Yes, self already
has a value when your initializer
starts. In fact, it is almost
guaranteed to be the correct, final
value.
-- Unquote
Essentially, I think a lot of people are left confused as to what each init method's 'self' is pointing to exactly, up through the superclass chain.
The answer to this riddle is implied in Apple's Objective-C Programming Language doc, under the section titled Designated Initializers:
Note that B version of init sends a
message to self to invoke the
initWithName: method. Therefore, when
the receiver is an instance of the B
class, it invokes the B version of
initWithName:, and when the receiver
is an instance of the C class, it
invokes the C version.
Or, in other words, the 'self' variable points to the our instance that is being initialized. Again to reemphasize, all of these init methods up through the superclass chain are inherited by our instance, and as such, the 'self' variable in them points to our instance (unless explicitly changed) .
Am I right? Of course!

Why the Objective C method still can be invoked when object was released?

Class definition:
#import "MyClass.h"
#implementation MyClass
- (id)init
{
self = [super init];
if (self) {
// Initialization code here.
}
return self;
}
- (void)dealloc
{
[super dealloc];
}
- (void)print
{
NSLog(#"Hello World");
}
#end
And main file:
MyClass * m = [[MyClass alloc]init];
[m print];
[m release];
[m print];
Result:
Hello World
Hello World
Why the 2nd method still invoked when object is released?
Releasing an object simply marks the memory it used as being available to be reused for other purposes. It doesn't overwrite it with zeroes or anything like that. In your example, you haven't created any new objects, so nothing has had a chance to reuse the memory formerly known as "m".
This why it's a common pattern to release an object and assign nil to the pointer, to prevent accidental re-use of an invalid object:
[m release]
m = nil;
That's because the memory for that object still is in place and hasn't been overwritten with garbage yet. Also, the method in question doesn't rely on any other (released) instance variable. In short: it's just pure chance that it worked.
Try setting the environment variable NSZombieEnabled and running that again to see that you really just had "luck".
Accessing freed memory is undefined behavior. When you're invoking undefined behavior, anything can happen. This falls under the heading of "anything," so it's a reasonable thing to have happen — so is accessing the wrong object or just crashing, which are also likely outcomes.