Is reference counting the same as ownership counting? - objective-c

Consider the following statement from "Big Nerd Ranch: Objective-C Programming" - Chapter 21: Object Instance Variables and Properties:
When an object has an object instance variable, the object with the pointer is said to own the object that is being pointed to.
Now consider the following scenario:
#import <Foundation/Foundation.h>
int main(int arc, const char * argv[])
{
#autoreleasepool {
NSString *message = #"Hello, world!";
}
return 0;
}
Here, the message object has one (1) reference. But... does it have any owner(s)?
If we strictly stick to the cited definition, there is no object with a pointer referencing this NSString. Does that mean that message has one (1) reference but no (0) owners?
And, if that is the case, what does ARC take into account when deciding whether to deallocate an object? Reference count or ownership count?

Reference counting is simply a number maintained by the object.
Ownership is a policy, almost a philosophy. It is a way of thinking that tries to ensure that you intervene coherently with an object's reference count.

Related

No matching function for call to pthread_create Objective-C ARC conversion

converting my project to ARC but says it can't due to the following error 'No matching function for call to pthread_create'. Here is the code it falls in, happens specifically on the line starting with pthread create. How can I fix this? It also says Candidate function not viable: no known conversion from 'NSString *' to 'void * _Nullable' for 4th argument in the sidebar underneath the error.
I've cut off the rest of the function but can provide more detail if necessary.
void World::loadWorld(std::string name)
{
if(doneLoading==0)
{
doneLoading=1;
Resources::getResources->stopMenuTune();
if(LOW_MEM_DEVICE)
{
menu->deactivate();
Resources::getResources->unloadMenuTextures();
terrain->allocateMemory();
terrain->loadTerrain(name,TRUE);
doneLoading=2;
hud->fade_out=1;
}
else
{
terrain->allocateMemory();
pthread_t foo;
pthread_create(&foo,NULL,loadWorldThread, nsstring(name));
}
}
As your error message indicates the 4th argument to pthread_create is of type void *. Under ARC you cannot simply pass an Obj-C object reference as a void * as ARC would is not able to track the reference once it is stored in a C(++) pointer variable, and therefore cannot manage the object's memory.
For situations where an Obj-C reference must be passed into the C(++) world a bridge cast can be used to inform ARC how the memory should be managed. However in your case there a better way, just pass the C++ pointer, name, without creating an NSString. If loadWorldThread expects a std::string that is the correct thing to do anyway. If it expects an NSString * then either:
modify it to take a std::string and do any required conversion to NSString * within it; or
write a small intermediate function which takes a std::string, produces an NSString * from it, and then calls loadWorldThread. Pass this new function to pthread_create.
Doing either of the above avoids the use of a bridge cast in the pthread_create call to move the Obj-C reference into the C(++) world and out of ARC control; and another bridge cast in loadWorldThread (or intermediate function as above) to move it back into the Obj-C world and into ARC control.
Addendum
Expanding on the last paragraph, as the method there seems better suited to your situation. First, it is assumed that your code:
nsstring(name)
takes a value of type std::string and returns a value of type NSString, if it does not then look up how to do this conversion.
After the above expression you have a reference to an NSString under ARC control. You cannot simply pass such a reference as a void *, you must take it out of ARC's control first and take responsibility for its memory management (but not for long as you will see). You can bridge cast your NSString * to a CFStringRef:
CFStringRef cfName = (__bridge_retain CFStringRef)nsstring(name);
You can now pass cfName, which is a reference to a heap-allocated CFString, as a void *.
Now in loadWorldThread; which should be declared to take a void *, something like void loadWorldThread(void *arg) { ... }; you need to bridge cast your CFStringRef back to NSString * and hands responsibility for its memory management back to ARC:
NSString *nsName = (__bridge_transfer NSString *)arg;
The above is a standard pattern to pass an ARC controlled reference though an anonymous reference (void *).
(Note: the above uses CFStringRef to make it clear that you are passing around a reference to a manually managed CFString, you can cast directly to void * and back again, indeed you will notice that when casting back arg was not first cast to a CFStringRef to demonstrate this.)
HTH

Declaring An Objective-C Object Without Alloc, Init, Or New

Sometimes I see object pointers set, without allocating or initializing them. For example:
MyObject *object;
And then it will be later assigned to a value. My guess is that this is more efficient, or a good way to not use memory until it's needed?
I've found answers like this one that touch on it, but I don't have much background in C++ or Java. If there are any Redditers out there, or someone who could Explain Like I'm Five, I'd love that.
MyObject *object;
That declares a reference to an object. It doesn't declare an object at all, nor does it allocate any memory.
You can easily copy an already existing reference to that reference, no need to allocate anything first:
object = [myThingamabob giveMeAnObject];
It is identical to doing this in C:
int main(int argc, char *argv[]) {
char *dogstring;
dogstring = argv[0];
}
In ELI5 terms:
Say you have a business card holder. It is empty. You don't have to put a blank card in it before putting a card given to you by another person. You can just put the received card straight into the box.

How does this Objective-C code work?

Code:
int main(int argc, const char * argv[]) {
id idObject = #"12345";
NSNumber *n = idObject;
NSLog(#"%#\n", [n description]);
return 0;
}
It prints "12345". How? I guess it's because Objective-C uses dynamic binding. Thus, decision which method to choose is made at run-time and this decision is based on the name of the method (selector) and the receiver object. Maybe the receiver object gets known due to "isa" pointer... ?
This works because:
All objects that inherit from NSObject have a description method.
Objective-C doesn't enforce types, so n is actually an NSString and not an NSNumber as you might suppose.
You are right.
The code works, because n refers to an object that understands the message description. (The object is a instance object of class NSString and these objects understand that message.)
The type of the object reference n (id, NSString*, NSNumber*, whatever) is without any meaning for the dispatching process.
At runtime you can collect many information about objects and its types. You cannot collect information about object references. (There is a single case, but this is not important.)
To add:
You're not actually typecasting by setting idObject to be referenced by NSNumber * n. The compiler doesn't know what type id should be, so it allows you to assign it to anything.
With your code snippet running you can see a bit more on how this is played out:
And then for comparison (creating an NSNumber from the string literal):

ARC does not dealloc when pointer is set to nil (using factory methods)

Edit: Problem defined below actually occurred with this code:
int main(int argc, const char * argv[])
{
#autoreleasepool
{
XYZPerson *myPerson = [XYZPerson person];
myPerson = nil;
NSLog(#"The end.");
}
}
The method 'person' is a factory method.
I have the following code:
int main(int argc, const char * argv[])
{
#autoreleasepool
{
XYZPerson *myPerson = [[XYZPerson alloc] init];
myPerson = nil;
NSLog(#"The end.");
}
}
XYZPerson overrides dealloc method so that it prints out something with NSLog. I expect the code above to output something like:
Dealloc!
The end.
But it is not as I expected:
The end.
Dealloc!
Am I doing something wrong or did I misunderstand the concept of ARC?
ARC guarantees that objects will be automatically reference counted at compile time. It goes further and places the requirement that the code be algorithmically fully coherent (which manifests as errors when trying to convert between, say, void* and id via casting -- under ARC, you have to qualify the memory management policy across such casts).
ARC is not a garbage collector; there is no scanning, no threading, and no stop-the-world behavior. This means more predictable behavior at the cost of things like automatic cycle detection.
While ARC guarantees that an object's lifespan will be automatically managed, ARC does not guarantee that lifespan beyond "the object will live for at least as long, maybe longer, than it is used in the code".
In fact, you might see lifespan changes depending on both the optimization level of the code and whether or not the factory method you invoked is compiled in an ARC vs. manual-retain-release [MRR] source file. And the lifespan may change across releases of the compiler and/or runtime.
For example, ARC code calling into a factory method can sometimes short-circuit the autorelease entirely.
Sounds scary, but it isn't because of the algorithmic coherence requirement. Since there cannot be ambiguous behavior (as there can in plain old MRR), that the lifespan might change over releases should not impact your code.
Of course, this means that you should not have order dependencies between dealloc methods. This should not be an onerous requirement as having order dependencies between dealloc methods under MRR was always a nasty thing.
This is because ARC still respects the Cocoa memory-management naming conventions. You can add attribute to Your factory method person like this: + (instancetype)person __attribute__((objc_method_family(new))); so ARC assumes that the object it returns comes with an incremented retain count that will need to be balanced with a corresponding release. Then immediately after setting variable to nil the dealloc will occur.

New to Objective C: Need help understanding strong reference vs assign

first post. Sorry if I screwed up the code rules. I'm trying to learn Objective C from the Big Nerd Ranch Guide. I'll post the example dealing with strong references.
#import <Foundation/Foundation.h>
#interface Asset : NSObject
{
NSSTRING *label;
unsigned int resaleValue;
}
#property (strong) NSString *label;
#property unsigned int resaleValue;
#end
So basically the NSString needs a strong reference whereas the int does not. I'm aware that NSString is an object, and I've read that if nothing is specified a variable is given the property of assign.
So if assign is good enough to keep something like an int from being freed until the object owning it is freed, how come it's not good enough to keep the NSString object within the Asset object from being freed? Ultimately I guess I'm still confused about what assign does in terms of reference counting vs. what strong does (or perhaps I should say retain since that is what strong replaced in ARC).
strong == to std::shared_ptr if you come from C++
strong states that the object must be retained and released respectively during assignment.
-(void)assign:(id) b to:(id) a {
if( b ){
[b retain];
}
if ( a ){
[a release];
}
a = b;
}
To answer your second question, the size of an objective-C object is not defined like a structure. Thus obj-C classes can not be held by value.
Thus all data inside of an obj-c class compiled as obj-c will always have plain old data types stored within it since their size can be determined as fixed.
Consider a buffer of 8 bytes;
The first 4 bytes are for your int the second 4 bytes are your pointer, since having a variable length string would change the size of the object at run time you see how this wouldn't work, a string is allocated on the heap and assigned to your pointer.