I have read the memory management guide from Apple and I don't see where this case is explained...
Many times, especially when writing a class method to return an instance of a class, I'll start it out like this, because that's how I've seen it done, and it works.
[NOTE] This code is from memory - I'll update it when I get home to show an example that really works (I made this up to illustrate it, but obviously I don't recall it well enough to construct something that makes sense...
[EDIT] Here's my actual method - of course everyone was right that I must be calling alloc which I am.
+ (id)player
{
Player *player = nil;
if ((player = [[[super alloc] initWithFile:#"rocket.png"] autorelease])) {
[player setProjectileType:kProjectileBullet];
[player setProjectileLevel:1];
[player setInvincible:YES];
[player setEmitter:[CCParticleSystemQuad particleWithFile:#"exhaust.plist"]];
[[player emitter] setPosition:ccp(0.0, player.contentSize.height/2)];
[player addChild:player.emitter];
}
return player;
}
So what I got from the responses is:
* Declaring the instance just gets me a pointer to a memory location and tells Xcode what class the object will be.
* Setting the pointer to nil pretty much just sets it to zero - keeping it from having garbage in it (right?)
* Since I'm autoreleasing the instance, the object that is returned is also autoreleased.
Thanks for helping me understand this!
Can someone explain what the compiler does when it sees this?
DooDad* aDooDad = nil;
If you are really interested in what the compiler does, the answer is: the compiler will reserve some memory on the stack for the local variable aDooDad, which is a pointer type (it is generally 64 or 32 bits in size depending on the processor). That pointer is then initialized to contain nil (usually 0x00..00).
A statement like this:
DooDad* aDooDad = [[DooDad alloc] init...];
makes use of pointer variable aDooDad to store the address in memory of the object that is further allocated (which is the address of memory reserved by alloc).
So, in the end,
DooDad* aDooDad = nil;
is not declaring an object, just a variable whose content is interpreted as the address of an object of DooDad type. Such declaration, therefore, is just like any other declaration you know, e.g. when initializing an int to 0, so that later you can assign it some value in an if statement.
A statement like:
[aDooDad doSomething];
is interpreted by the Objective-C runtime system like: send message doSomething to the object whose address is stored in aDooDad. If that address is nil no message is sent. On the other hand, if you dereference a nil pointer: *aDooDad you'll get undefined behavior.
Pointers are pretty low level stuff. I hope this helps.
If you're familiar with C or C++, variables can be created in one of two ways, statically on the call stack, or dynamically on the heap. Variable memory created on the stack is is reclaimed when the current stack frame goes out of scope, so you never need to worry about creating or destroying it. In Objective-C, objects are always dynamically created. Primitives (like int, float, pointers, etc), can either be statically or dynamically created. For illustration:
- (id)something {
NSObject myObject; // Illegal static object allocation
NSObject* myObject; // Legal primitive (pointer) static allocation
int myInt; // Legal primitive static allocation
int* myIntPtr; // Legal primitive (pointer) static allocation
}
So when you say DooDad* dodad = nil;, you're creating a primitive (pointer to a DooDad) on the stack. Being a stack variable, you don't alloc or dealloc it, just like you wouldn't worry about alloc'ing or dealloc'ing any of the memory in the following method:
- (id)allStackVariables {
int myInt = 0;
float myFloat = 0.0f;
float* myFloatPtr = NULL;
NSObject* myObject = nil;
}
Setting it to nil simply sets the contents of the variable to whatever the compiler defines to be nil, something like 0x000000 in hex. Saying DooDad* dooDad = nil; is conceptually identical to saying something like int myInt = 0;
Declaring simple gives you a pointer you can use later. No memory is allocated.
Not sure what the intent of the method you posted, but it seems wrong on many levels. It will return nil, always. Unless it's an initializer method, it should not call [self init]. If it is an initializer method, it should return self and be named something like "init..."
Related
Is it possible (and if so, safe) to create/use a block which takes a double pointer as an argument?
For instance:
- (void)methodWithBlock:(void (^)(NSError **error))block;
Additional context, research, and questions:
I'm using ARC.
When I declare the method above and attempt to call it, XCode autocompletes my method invocation as follows: [self methodWithBlock:^(NSError *__autoreleasing *error) {}];
What does __autoreleasing mean here and why is it being added? I presume it has something to do with ARC.
If this is possible and safe, can the pointer still be dereferenced in the block as it would be anywhere else?
In general, what are the important differences between doing what I'm describing, and simply passing a double pointer as a method parameter (e.g. - (void)methodWithDoublePointer:(NSError **)error;)? What special considerations, if any, should be taken into account (again assuming this is possible at all)?
yes, pointers are always just pointers. you only need to make sure you dereference it before sending it a message (assuming objc object).
Also be aware that the pointer may be nil. always check it before trying to dereference it or what have you.
As #verec mentioned if you are using ARC you should declare the parameter as __autoreleasing
according to the docs
__autoreleasing is used to denote arguments that are passed by reference (id *) and are autoreleased on return.
remember id is a pointer to an object so that is saying object**
there is no difference between passing pointers to pointers to methods or blocks.
The answers are both Yes & No...
At a base level passing pointers to pointers to blocks is no different than passing them to methods; and, with the usual proviso that your pointers must be valid, is perfectly OK.
However that __autoreleasing is very significant here and is tied up with ARC and pass-by-writeback. Whether using the block will work as expected will be dependent on context as the compiler often uses hidden variables when passing parameters of type NSError * __autoreleasing * as part of the pass-by-writeback implementation.
If pass-by-writeback is not what you need, or is unsuitable, you may wish to declare you block as taking a different type, such as NSError * __strong *. Read this answer which explains what happens under the hood, that should help you decide whether in your context the block declaration is good.
In summary (a) declaring the block is fine, but (b) you need to understand how it may be called and may need to change the signature.
warning: untested
For the sake of argument, let's start with:
typedef NSError * NSErrorPtr ;
- (void) foo: (NSErrorPtr *) errPtr {
*errorPtr = [NSError new] ;
}
errPtr isn't declared either __weak nor __strong.
So, according to ARC, even though its contents is allocated within foo the responsibility for releasing it has to reside somewhere.
Where?
Note that this not a property of double pointers per se. But of your pattern of allocation.
consider:
int ** arrayOfarrayOfInts = {
{1, 2, 3, 4}
, {5, 6, 7, 8}
} ;
- (void) incrementElement: (int **) elem {
++(**elem) ;
}
- (void) bumpFirstColByOne {
for (int i = 0 ; i < 2 ; ++ i) {
int * arrayOfInt = arrayOfarrayOfInts[i] ;
int ** second = &arrayOfInt[0] ;
[self incrementElement: second] ;
}
}
No __autoreleasing needed here because no allocation is taking place ...
__block NSString *x = #"123"; // x lives in block storage
void (^printXAndY)(NSString*) = ^(NSString *y) {
x = [x stringByAppendingString:y];
printf("%# %#\n", x, y);
};
printXAndY(#"456");
Apple docs says:
The __block Storage Type You can specify that an imported variable be
mutable—that is, read-write— by applying the __block storage type
modifier.
If the x is mutable, isn't this x = [x stringByAppendingString:y]; wrong? and can cause memory leaks?
First, you are confusing two completely unrelated things: 1) the variable being assignable (i.e. non-const), and 2) if the variable is of object pointer type, the object it points to being "mutable".
Non-__block local variables are const inside a block, which means you can't do x = something. Making the variable __block allows you to do x = something inside the block (regardless of the type of x). When x is a pointer variable, assignment to it makes it point to something else.
So-called "mutating" a "mutable" object just means you can call a method on it that somehow changes the "contents" of the object. It does not involve assigning to any pointers that may point to this object.
As to your second question, memory leaks, no, there shouldn't be any memory leaks. First of all, if you're using ARC, it's obvious that there are no leaks. Even if you are using MRC, there are no leaks. In fact, if this is MRC, none of the object pointers in this code has been retained by your function (they are not the result of retain, alloc, new, copy, etc.), so there cannot possibly be a leak.
I'm trying to implement the countByEnumeratingWithState:objects:count: method from the NSFastEnumeration protocol on a custom class.
So far I have it iterating through my objects correctly, but the objects that are returned aren't Objective-C objects but rather the core foundation equivalents.
Here's the part of the code that sets the state->itemsPtr:
MyCustomCollection.m
- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState *)state
objects: (id __unsafe_unretained *)buffer
count: (NSUInteger)bufferSize {
// ... skip details ...
NSLog(#"Object inside method: %#", someObject);
state->itemsPtr = (__unsafe_unretained id *)(__bridge void *)someObject;
// ... skip details ...
}
Then I call the 'for..in' loop somewhere else on like this
SomeOtherClass.m
MyCustomCollection *myCustomCollection = [MyCustomCollection new];
[myCustomCollection addObject:#"foo"];
for (id object in myCustomCollection) {
NSLog(#"Object in loop: %#", object);
}
The console output is:
Object inside method: foo
Object in loop: __NSCFConstantString
As you can see, inside the NSFastEnumeration protocol method the object prints fine, but as soon as it gets cast to id __unsafe_unretained * I lose the original Objective-C corresponding class.
To be honest I'm not quite sure how the (__unsafe_unretained id *)(__bridge void *) casting works in this case. The (__unsafe_unretained id *) seems to cast to match the right type itemsPtr needs. The (__bridge void *) seems to cast to a pointer of type void with __bridge used to bridge the obj-c world to the CF world. As per the llvm docs, for __bridge:
There is no transfer of ownership, and ARC inserts no retain operations
Is that correct?
From my understanding __NSCFConstantString is just the core foundation equivalent of NSString. I also understand that with ARC you need to bridge from Objective-C objects to CoreFoundation equivalents because ARC doesn't know how to manage the memory of the latter.
How can I get this working so that the objects in my 'for..in' loop are of the original type?
Also note that in this case I'm adding NSStrings to my collection but in theory it should support any object.
UPDATE
Rob's answer is on the right track, but to test that theory I changed the for loop to this:
for (id object in myCustomCollection) {
NSString *stringObject = (NSString *)object;
NSLog(#"String %# length: %d", stringObject, [stringObject length]);
}
In theory that should work since the objects are equivalent but it crashes with this error:
+[__NSCFConstantString length]: unrecognized selector sent to class
It almost looks like the objects returned in the for loop are classes and not instances. Something else might be wrong here... Any thoughts on this?
UPDATE 2 : SOLUTION
It's as simple as this: (thanks to CodaFi
state->itemsPtr = &someObject;
You're incorrectly casting someObject. What you meant is:
state->itemsPtr = (__unsafe_unretained id *)(__bridge void *)&someObject;
(Let's get rid of those awful casts as well)
state->itemsPtr = &someObject;
Without the address-of, your variable is shoved into the first pointer, which is dereferenced in the loop. When it's dereferenced (basically, *id), you get the underlying objc_object's isa class pointer rather than an object. That's why the debugger prints the string's value inside the enumerator call, and the class of the object inside the loop, and why sending a message to the resulting pointer throws an exception.
Your code is fine the way it is. Your debug output is revealing an implementation detail.
NSString is toll-free-bridged with CFString. This means that you can treat any NSString as a CFString, or vice versa, simply by casting the pointer to the other type.
In fact, under the hood, compile-time constant strings are instances of the type __NSCFConstantString, which is what you're seeing.
If you put #"hello" in your source code, the compiler treats it as a NSString * and compiles it into an instance of __NSCFConstantString.
If you put CFSTR("hello") in your source code, the compiler treats it as a CFStringRef and compiles it into an instance of __NSCFConstantString.
At run-time, there is no difference between these objects in memory, even though you used different syntax to create them in your source code.
i have two Objective-C classes, say ParentLayer and ChildLayer. in my child instance, i want to access a C-Array in my parent instance. so i have something like this in my cocos2d code:
#define kNumOfElements 10
#implementation ParentLayer{
int array[kNumOfElements];
}
-(id)init{
//...
for(int i=0;i<kNumOfElements;i++){
array[i] = i;
}
[self addChild:childLayer];
[childLayer initializeValues];
//...
}
-(int *)getArray{
return array;
}
#end
//meanwhile in my child layer...
//...
-(void)initializeValues{
int *arr = [(ParentLayer *)[self parent] getArray];
//NSLog(#"%d",arr[0]); <------- this gives you bad exec access point, and looks like it's 0x00 for memory address
}
//...
what's the proper way to do this?
maybe i dont understand the right memory management behind C Arrays.
i was under the impression that C Arrays didn't need to be allocated,
and that they could be passed by value, on the stack?
also, shouldn't my parent instance still be around? i thought if i
put a C Array as an ivar of my parent, it shouldn't get destroyed
any help is appreciated. thanks!
what's the proper way to do this?
Ideally, you should never pass a C-style array pointer outside of the object that owns it. You open yourself up to all sorts of problems if a piece of code tries to use the array after the object is deallocated, or writes past the end, or something else. It is easier to guarantee that none of this happens if you can make sure the reference never leaves the object's source file.
maybe i dont understand the right memory management behind C Arrays. i was under the impression that C Arrays didn't need to be allocated, and that they could be passed by value, on the stack?
It is not that simple.
A C-style array is just a memory address. That's it. It doesn't carry around the other useful information that an object might, such as number of elements, retain count.
If you declare an array like this:
int array[100];
Then the memory is allocated in either the stack or the heap, depending on where you put the declaration. If it's a local variable inside a function or method, it's on the stack. If it's in global scope or a member variable of an object, it's on the heap.
Furthermore, if it's an instance variable, you're actually setting aside 100 ints worth of memory inside the block of memory allocated to hold the object. It isn't a separate thing.
Since array is just a memory address, you are basically passing it around by reference. Technically, you are passing the address by value, but any changes you make to the memory will be seen by anyone looking at the same address, so it acts like pass by reference.
also, shouldn't my parent instance still be around? i thought if i put a C Array as an ivar of my parent, it shouldn't get destroyed
The way you have coded it, that array will be valid as long as the parent object is around. Once the parent gets deallocated, that memory could be reclaimed. Since the array variable is just a memory address, however, you have no way of knowing whether the data it points to is valid or not. This is the danger of using C-style arrays rather than objects.
Since the last line is giving you NULL (0) address, my guess is that [self parent] is nil. That would put a 0 in arr; when you try to dereference NULL, you will get an exception.
In Objective C, you can use property for this.
#define kNumOfElements 10
#interface ParentLayer: NSObject
{
int *array;
}
#property(nonatomic, assign) int *array;
#end
#implementation ParentLayer
-(id)init{
//...
self.array =(int*)malloc(sizeof(int) * kNumOfElements);
for(int i=0;i<kNumOfElements;i++){
self.array[i] = i;
}
[self addChild:childLayer];
[childLayer initializeValues];
//...
}
//-(int *)getArray{
// return array;
//}
-(void)dealloc
{
if(self.array)
{
free(self.array); self.array = NULL;
}
[super dealloc];
}
#end
-(void)initializeValues{
ParentLayer *player = (ParentLayer *)[self parent] ;
int *arr = player.array;
//NSLog(#"%d",arr[0]); <------- this gives you bad exec access point, and looks like it's 0x00 for memory address
}
can't seem to add a reply to benzado's post. but depending on how to declare your object, it might be automatically deallocated. to ensure that it is retained, use a retain keyword.
[obj retain];
especially using the cocos2d framework, they have quite a number of auto release objects. typically initWith shouldn't be auto release.
Here is the problem:
I am passing a pointer to an object to performSelector:withObject via [NSValue valueWithPointer:] for example like this:
// GVertex is NSObject subclass
GVertex *vertex = [[GVertex alloc] initWithX:5.0f andY:4.5f]];
GVertex **vertexPtr = &vertex;
// later in code when I need to process the vertex
[self performSelector:#selector(processVertex:) withObject:[NSValue valueWithPointer:vertexPtr]];
then in my processVertex:(NSValue *)vertexValue method I want to get the passed vertex and I do it like this:
- (void)parseVertex:(NSValue *)vertexValue
{
GVertex *vertex = (GVertex *)[vertexValue pointerValue];
...
[vertex setFlags:32]; <<-- This gives me EXC_BAD_ACCESS
...
}
I have tried many combinations of (*) and (&) everywhere but can't get it to work.
What am I doing wrong ? Thanks.
Why don't you just pass your vertex object:
[self performSelector:#selector(processVertex:) withObject:vertex];
and change your method declaration to:
- (void)parseVertex:(GVertex *)vertex {
[vertex setFlags:32];
}
The pointer you're putting into the NSValue is a pointer to a pointer (or the address of a pointer), but you're retrieving it as if it's a plain object pointer. Moreover, the pointer whose address you're taking is a local variable -- that address is going to be garbage in the context of a new method.
This should work if you just store the (single) pointer in the NSValue:
[self performSelector:#selector(processVertex:) withObject:[NSValue valueWithPointer:vertex]];
Beware of memory management issues, however -- NSValue does not copy or take ownership of the memory at that pointer.