Given the following variable declaration,
Foo* foo;
how is memory actually being allocated?
This is my guess. There are actually two pieces of memory being allocated here.
A 32 bit number representing a memory address stored at foo [The pointer]. How exactly does the compiler mark or signal that the pointer is actually storing a reference to memory that is of type of Foo?
A contiguous memory segment that is uninitialized and typed as Foo. How does it know how much memory to allocate? How does it mark the memory segment as being of type Foo?
The line of code you've given doesn't allocate any memory. At most, it moves the stack pointer sufficiently to make room for a one-word value (though after optimization, it may not even do that).
A 32 bit number representing a memory address stored at foo [The pointer].
By "32 bit number" I assume you mean "a pointer-sized integer" which is 64 bits on most modern processors. This may, if it's not optimized, be aliased to some location on the stack.
How exactly does the compiler mark or signal that the pointer is actually storing a reference to memory that is of type of Foo?
It doesn't signal this, and it doesn't store a reference to memory that is of any type at all. The above line of code just (at most) makes room for a pointer. In ObjC, at runtime there are no object types. Every pointer to an object is considered id. ObjC absolutely does not promise that this represents a "contiguous memory segment" (there are plenty of cases where what you would think of as "the data" is not contiguous). At a deeper level, the processor does not care about "types" at all. There is just memory and pointers (void *) to memory. (At a deeper level than that, there isn't even "memory." There's physical RAM, caches, registers, and many other things that are generally abstracted away, even in C. For more on that, see C is not a Low-Level Language.)
A contiguous memory segment that is uninitialized and typed as Foo. How does it know how much memory to allocate? How does it mark the memory segment as being of type Foo?
This isn't allocated at all by the above line. If you want to allocate memory for Foo, you must call +[Foo alloc]. Since it is a class method on Foo, it knows how much memory Foo requires. Nothing marks that memory of being of any type, and Objective-C does not actually care what type it is. All it cares is that theres a pointer in the right place called the isa pointer that it can use to lookup how to dispatch messages via objc_msgSend.
There are plenty of cases where something called *Foo does not point to a Foo. It's very common that the actual thing pointed to is a toll-free-bridged type, which is a data structure for a completely different type (a CF structure) that happens to have an isa pointer in the right place so that it can pretend to be an ObjC object. All that is required for the system to work is for things to line up "close enough" that objc_msgSend can function. There is no need (or mechanism) for marking memory as being some particular type.
The size of a pointer like Foo * depends on the target platform. On most current Apple platforms, it is 64-bit, but Apple Watch prior to Series 4 is 32-bit.
There are several contexts in which you might write this:
Foo *foo;
You could write this as a global variable, outside of any #interface or #implementation variable declaration and outside of any function. Then, each time the program is started, it allocates space for one pointer and sets that pointer to nil.
You could write this in an #implementation variable declaration, like this:
#implementation MyObject {
Foo *foo;
}
In this case, you have declared an instance variable (or “ivar”). Each time the program creates an instance of MyObject, the instance includes space for one pointer and sets the pointer to nil.
You could write this as a local variable in a function or a method, like this:
- (void)doSomething {
Foo *foo;
}
In this case, you have declared a local variable. Each time the function or method is called, it allocates one pointer in its stack frame and (assuming you compiled with ARC enabled, which is the default) it initializes the pointer to nil.
Note that in all of these cases, foo does not point to an instance of Foo. It points to nil. To make foo point to an instance of Foo, you must set it to reference to Foo that you got from somewhere else. You could get that reference by calling a function or method, like this:
- (void)doSomething {
Foo *foo;
// foo is nil here.
foo = [[Foo alloc] init];
// If [[Foo alloc] init] succeeded, then foo now points to an
// instance of Foo. If [[Foo alloc] init] returned nil, which
// indicates failure, then foo is still nil.
}
Or you could be passed a Foo reference as a function argument:
- (void)doSomethingWithFoo:(Foo *)incomingFoo {
Foo *foo;
// foo is nil here.
foo = incomingFoo;
// foo now points to whatever incomingFoo points to, which should be
// either an instance of Foo, or nil.
}
Or you could get it from some other global, local, or instance variable.
As to “How exactly does the compiler mark or signal that the pointer is actually storing a reference to memory that is of type of Foo”: It doesn't. At compile-time, the compiler knows that foo should only point to a Foo (or nil), and tries to prevent you from assigning it to things that aren't a pointer to Foo. For example, the compiler will issue a warning or an error for this:
Foo *foo = #"hello";
because the compiler knows that an NSString is not a Foo. (I assume you didn't make Foo a typedef or subclass of NSString.)
However, you can override the compiler's type concerns using a cast:
Foo *foo = (Foo *)#"hello";
or by using the id type:
id something = #"hello";
Foo *foo = something;
This compiles, and it runs fine until you try to do something with foo that an NSString doesn't know how to do.
So it's not the compiler that knows “the pointer is actually storing a reference to memory that is of type of Foo”.
The Objective-C runtime knows that the pointer is actually storing a reference to a Foo. To understand how the runtime tracks the type of an object, you first need to know about the Foo class object.
For every Objective-C class in a program, there is, at runtime, one special object called the “class object”. So for NSObject, there is a single NSObject class object, and for NSString, there is a single NSString class object, and for Foo, there is a single Foo class object. Note that in general, a class object is not an instance of itself! That is, the NSString class object is not itself an instance of NSString, and the Foo class object is not itself an instance of Foo.
The Foo class object knows what makes up an instance of Foo:
The superclass of Foo (maybe NSObject, maybe something else).
The name, type, and size of each instance variable of a Foo (except those inherited from the super class of Foo).
The name, type signature, and implementation address of each message understood by a Foo (except those inherited from the superclass of Foo).
The first bytes of every Objective-C object contain a pointer to a class object.1 This pointer is called the isa pointer, and it determines the type of the object. When you use the syntax that sends a message to an object, like [foo length], the compiler generates a call to objc_msgSend. Recall that in [foo length], the object referenced by foo is called the receiver. The objc_msgSend function uses the isa pointer of the receiver to find the receiver's class object. It looks through the class object's table of messages to find the implementation of length and jumps to it. If Foo doesn't define a length message, then objc_msgSend looks in Foo's superclass for the message, and so on up the superclass chain.2
So, it is this isa pointer that determines the type of the object at runtime.
So how does a Foo object get allocated? When you say [[Foo alloc] init], that means “send the alloc message to the Foo class object, and then send the init message to whatever comes back from alloc”. So the Foo class object receives the alloc message. But the Foo class object probably doesn't implement alloc directly. It inherits the NSObject implementation of alloc.
So +[NSObject alloc] actually allocates the memory for a new Foo. As you say, it allocates a “contiguous memory segment”, but it is not “uninitialized and typed as Foo”. It is initialized and type as Foo. The +[NSObject alloc] documentation says:
The isa instance variable of the new instance is initialized to a data structure that describes the class; memory for all other instance variables is set to 0.
You can look at the implementation here. It's the callAlloc function. It uses the standard C library function calloc to allocate memory, and calloc fills the memory to 0. Then it sets the isa pointer.
As to “How does it know how much memory to allocate”: remember that each class object knows all of the instance variables of its instances. So to allocate a Foo, +[NSObject alloc] sums the sizes of all of the instance variables of a Foo, plus the sizes of all of the instance variables of Foo's superclass, recursively to the end of the superclass chain. That tells it how many bytes to allocate. Except that it would be too slow to do that every time it allocates an object. So the program pre-computes the instance size for every class object at startup, and +[NSObject alloc] looks up the precomputed size of a Foo in the Foo class object.
Unless the object is represented as a tagged pointer, but don't worry about that.
If you want to know what happens when objc_msgSend reaches the end of the superclass chain without finding an implementation, read Objective-C Message Forwarding.
Related
I am having problem with understanding one concept of memory managment, because I am new to objective C. For instance lets say I have a class Bar and Foo.
in main function I call:
Foo *foo = [bar getFoo]; //In my bar method I return foo
[foo retain];
[foo callMethod];
[foo release];
I know this is right way to do it. But why do we have to retain it after we get it from another object, does not this mean returning object has retain count 0 ? so we have to reatin it to count 1 to use it? but if it has reatin count 0, how do we know it is still there. We can assume since it is the next line that increment retain count that the object memory wont be realocated, but what if we have multi-threading program?
When an class method returns an object, it will autorelease it so you don't have to bother; typically:
- (Foo *)getFoo
{
return [[_foo retain] autorelease];
}
If you are only using foo for the lifetime of the calling method you don't need to retain it, as it won't be autoreleased until next time through the run loop, so your code should actually be:
Foo *foo = [bar getFoo]; //In my bar method I return foo
[foo callMethod];
If, however, you want to hold foo for a while, outside the scope of the calling method, you need to retain it and then release it sometime later.
One more thing; the convention for getter method names is simply "name", so your setter should be setFoo and your getter would be foo. Keeping to the naming conventions is a good idea as it lets you know what a method does, in say 7 months time, and tools like static analysis understand the conventions.
The method getFoo doesn't return an object with a 0 retain count. It returns an object with a +0 retain count which means that:
the object's retain count is not null (otherwise, the object wouldn't exist)
and the retain count wasn't altered by the invocation of the method, or if it was, it was in a balanced way (with as many release/autorelease as retain/alloc/new/copy).
Thus the lifetime of the object entirely depends on where and how it is retained. We don't know how long the object will be valid as any method invocation could release the object.
For example, let's consider the following code:
id anObject = [anArray objectAtIndex:0];
[anArray removeObjectAtIndex:0];
The object anObject isn't retained any more by the array as we removed it. Therefore it may have been destructed (but maybe it wasn't because it is still used somewhere else).
Generally, when getting an object from a method (other that alloc, copy, new or retain), we can assume that:
either the object was retained then autoreleased,
either the object is retained by the object that returned it.
So we know the object foo is valid until we return from the current method/function or we invoke a method/function that alter the state of the object bar, whichever comes first. After that, it may have been destructed.
So in your case, you can safely omit the retain/release pair.
However, it is very difficult to guaranty that an object doesn't get released unless we know the implementation of every method we invoke. Therefore, retaining (then releasing) every single object we get is the safer approach and that's what the compiler will do when you enable ARC (Automatic Reference Counting).
But that would require you to write a lot of retain/release and your code would become difficult to read, understand and maintain. Moreover, the more code you write, the more bugs you get (unless you never write bugs).
In conclusion, you don't need to retain an object unless you have a reason to suspect it could vanish otherwise.
I want to know why id is a weak reference pointer,how it is able to handle any class type pointer and at run time how can we detect that which type of class pointer is assigned to id.
Why is id a weak reference pointer?
id is not a weak reference pointer, at least not in the ARC ownership sense. Whether an id-typed reference to an object is weak or not depends on the reference having been declared __weak (and variations) and the object’s class actually supporting weak references.
However, you could say that id provides weak typing, although I think that dynamic/duck typing is a more accurate description. Since an id- typed reference contains no compile-time class-type information, the compiler isn’t able to, for example, determine if the underlying object can respond to a given selector, which could lead to runtime errors.
How is it able to handle any class type pointer?
That’s part of the definition of the Objective-C language. The compiler recognises id as being the supertype of every Objective-C class, and it treats id differently. See the answer below as well.
At runtime, how can we detect that which type of class pointer is assigned to id?
In Apple’s Objective-C runtime, the first bytes in the memory allocated to an object must point to that object’s class. You might see this referenced elsewhere as the isa pointer, and that’s how Apple’s runtime finds out the class of every1 object. The id type is defined to have this information as well. In fact, its only attribute is the isa pointer, which means that all1 Objective-C objects conform to this definition.
If you have an id reference and want to discover the class of the referenced object, you can send it -class:
id someObject;
// Assign something to someObject
// Log the corresponding class
Class c = [someObject class];
NSLog(#"class = %#", c);
// Test whether the object is of type NSString (or a subclass of NSString)
if ([someObject isKindOfClass:[NSString class]]) {
NSLog(#"it's a string");
}
1Tagged pointers are a notable deviation of this structure, and (partly) because of them one shouldn’t access the isa pointer directly.
It's nice to have a generic object type, so you can define collection types that can hold any kind of object, and other generic services that work with any object without knowing what kind of object it is.
There is no trick to make id work. At a binary level all pointers are interchangeable. They just represent a memory address as a numerical value. To make id accept any type of pointer, it's only necessary to disable the rules of the compiler that normally require pointer types to match.
You can find out information about the class of an id type variable in these kinds of ways:
id theObject = // ... something
Class theClass = [theObject class];
NSString *className = NSStringFromClass(theClass);
NSClassDescription *classDescription = [NSClassDescription classDescriptionForClass:theClass];
But it's rarely necessary to do those kinds of things in code. More often, you want to test if your id variable is an instance of a particular class, and if so cast it to that class and start treating it as that type.
if ([theObject isKindOfClass:[MySpecializedClass class]]) {
MySpecializedClass *specialObject = (MySpecializedClass *)theObject;
[specialObject doSomethingSpecial];
}
If you were to use -class to find out the class, but it returned a class you know nothing about, then there's nothing special you can do with the object based on its class anyway. So there is no reason to do anything but check if it matches classes you know about, and only if you intend to do special handling for those classes anyway.
You can sometimes use isMemberOfClass instead of isKindOfClass. It depends whether you want an exact match or to include subclasses.
It may be worth to take a look on header file objc/objc.h to find internals of id.
typedef struct objc_class *Class;
typedef struct objc_object {
Class isa;
} *id;
typedef struct objc_selector *SEL;
typedef id (*IMP)(id, SEL, ...);
How would I dealloc a boolean value?
Deallocing it this way below gives me a warning: Incompatible pointer to integer conversion assigning to 'BOOL' (aka 'signed char') from 'void *'
- (void)dealloc {
self.booleanVar = nil;
[super dealloc];
}
Perhaps I should clarify, this is from a simple class inherited from NSObject.
I'm using the self.var = nil pattern that you see in Cocoa Touch classes. Let's say if it was an NSString* instead should I use self.var = nil or [var release] in the deallocmethod? I'm a little confused here.
You don't need to do it. It is not an object. This also explains the warning, as you're trying to assign a nil pointer (that's a NULL for objects basically) to a non-object.
Regarding your second question, yes. You can think of primitive variables as being part of the object, so when it's deallocated the vars will not exist anymore.
But when you have a NSString * in an object, it's just a pointer to another object. If you dealloc the former, the pointer will be deleted, not the NSString. No one might point to it, it's kind of lost in the air, occupying memory. So, before deleting the pointer, if you won't need the object anymore, you send it a release message. That's done in the dealloc method, since it's called to "delete" and object and thus is a good place to delete also every other object that has no use anymore.
You dont need to dealloc a BOOL, since BOOLs are really just a byte, which is a primitive data type. You only need to dealloc objects which have been allocated to memory.
First of all, if booleanVar is just a plain BOOL value, as in it is declared like so:
BOOL booleanVar;
then you do not need to free up any memory associated with it, since that memory is allocated and freed when the class that holds it is allocated and deallocated. So no code for booleanVar in dealloc will be fine.
However, if you are talking about a pointer for a BOOL, defined like so:
BOOL *booleanVar;
and what you want is to set this variable to a non-value, you should set it equal to NULL instead of nil, since NULL is for value pointers and nil is for object pointers (see: NULL vs nil in Objective-C).
However, if what you want is to free up the memory that the BOOL pointer points to, allocated with malloc or realloc, etc, then try the free() C function (see: http://www.cplusplus.com/reference/clibrary/cstdlib/free/).
What would really clear all this up is if you showed us the property declaration for booleanVar in the class interface, which would tell us exactly what you want to do and you would get an answer with complete certitude.
This may seem like trivial question.
But why is that we have to use the asterisk symbol when declaring object variables
Like, we do
Car * mazda = [[Car alloc] init];
What's the importance of the asterisk, I mean the compiler already knows it's an object, I'm sure the compiler can be trained not to complain about it. But then again by omitting it, I get an error message "statically allocating instance of objective-c class NSObject" What purpose would that serve?
The asterix is a qualifier to the Car variable that you declaring. It means that you are declaring a pointer to a Car rather than declaring a Car itself. The return value of the init function (and the alloc function for that matter) is a pointer to a Car, not a Car itself, therefore this is correct.
With * you declare a pointer. That’s like in C, which is a subset of ObjC. Without the * the variable would be statically allocated which is not possible for ObjC objects (because the size of the object couldn’t be determined at compile time).
Statically allocated variables are used for primitive C types like int or double
int number = 42;
Objective-C requires that all objects are dynamically allocated (i.e. on the heap). The error you're getting indicates that you're trying to create a Car object on the stack. By declaring mazda to be a pointer to Car (Car*) rather than a Car, you satisfy that requirement.
This is effectively a dupe of Why [object doSomething] and not [*object doSomething]?, which has a ton of background information.
The asterix in variable declaration also means the value of the variable will not have a static allocated value. Its a pointer just like the others have said.
I had a couple questions related to this: Asterisk usage in Objective-C
NSArray array; in a local scope would be an object "allocated" on the stack. NSArray *array; indicates an object backed by a hunk of memory, typically allocated from the heap.
How do you know when something is allocated on the stack and on the heap? Are all local variables on the stack and are all pointers on the heap?
Because you aren't dereferencing the pointer to the object and that pointer to the object is critical within the method implementation itself. When you say...
Huh
How do you know when something is allocated on the stack and on the heap? Are all local variables on the stack …
It doesn't matter. The stack and heap are implementation details; the C and Objective-C languages do not know about them, and you should generally not have any reason to care whether something is on the stack or the heap.
On Mac OS X, local variables are on the stack. But, for almost all purposes, this is of no consequence. Don't worry about it.
… and are all pointers on the heap?
No. Pointers are memory addresses; that's all.
Pointer variables can be anywhere any other variables can, which is to say, anywhere (subject to implementation-defined limitations that you needn't care about, as noted above).
See my pointer tutorial for more information.
Because you aren't dereferencing the pointer to the object and that pointer to the object is critical within the method implementation itself. When you say...
Huh
A pointer is a memory address. As such, it refers to the memory at that address. Dereferencing the pointer is accessing that memory.
You never, ever directly access the memory a Cocoa object takes up. You only send it messages, to either ask it questions or tell it to do things. Thus, you never dereference the pointer.
“…that pointer to the object is critical within the method implementation itself.” means that the object, in its method implementations, will need its own pointer. It's only possible to send a message to a pointer to an object (this detail is usually elided). If you somehow pulled this off, the receiver of the message (that is, the object you messaged) would not have its own pointer.
Suppose it were possible to send a message to a dereferenced object. The norm is still to send messages to pointers to objects, so in all likelihood, the object will still need that pointer to itself—making that hypothetical ability to message a dereferenced object useless.
Since it's useless, they left it out entirely. The object will need its own pointer (the pointer is critical to the object's method implementations), so you can only send a message to its pointer.
The * is the dereference operator for C, C++ and Objective-C. Understanding the dereference operator, and memory management in general is far broader than Objective-C. This is a fundamental skill for any C/C++/Objective-C developer. Have a look at the multitude of intro C tutorials on the net to learn more.
Edit: any tutorial on c pointers will do. Such as this http://home.netcom.com/~tjensen/ptr/pointers.htm
In Cocoa, you'll never use stack allocated objects; ALL objects will be prefaced with a * (remember that the type "id"is really another word for "pointer to SOME object") and created on the heap.
You'll always have this:
NSArray *myArray;
and never this:
NSArray myArray;
You can ignore the second chunk, since you're always dereferencing the pointer.
Hope these naive toy examples can help you.
In C, in a function,
int x; // x is a variable of type int in stack
int *xp; // xp is a variable of type int * (pointer to int) in stack
int *xp2 = (int *) malloc(sizeof(int)); // xp2 is a variable in stack, it points to a memory location(size is of int) in heap
xp = &x; // xp can point to x
xp = xp2; // xp can also point to what xp2 points to
free(xp2); // now xp and xp2 point to a freed memory, BAD to use xp and xp2 now.
int **y; // y is a variable in stack, type is int **
y = (int **) malloc(sizeof(int *)); // allocate a piece of memory in heap, to hold a pointer to int(int *)
*y = (int *) malloc(sizeof(int)); // allocate a piece of memory in heap, to hold an int
**y = 100; // now we can use it
free(*y);
free(y);
In C++, in a function or member function(method),
SomeClass a1; // a1 is an object of type SomeClass in stack
SomeClass *a2 = new SomeClass(); // a2 is a pointer(in stack) pointing to an object(of type SomeClass) located in heap
delete a2;
So in C++, objects can exist in stack or heap
In Java, in a function or method,
SomeClass b1; // b1 is just a reference, no object exists yet
b1 = new SomeClass(); // in java, objects can only exist in heap
int x; // however, primitive types are in stack,
In Objective-C, in a function or method,
SomeClass c1; // you can't do this.
SomeClass *c2 = [[SomeClass alloca] init]; // c1 is a pointer in stack, pointing to an object in heap
[c2 release];