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

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.

Related

Meaning of #property (readonly) void *data; in Objective c

I am new to iOS programming, I am preferring Swift language and I don't know Objective C. While I am wandering through some library, I got a value of type UnsafeMutableRawPointer in swift, that is actually a String value with utf8 encoding.
So I just looked into the corresponding objective c class and the variable is declared as
#property (readonly) void *data;
So why there is void pointer and why it is converted as UnsafeMutableRawPointer?
Consider me as a noob in Objective c or c.
Thanks in advance
This whole thing might be quite a lot for a beginner to understand. So let's start with ObjectiveC syntax:
Property #property (readonly) void *data; exposes interfaces which says there must be a method of type - (void *)data which means an instance method returning a void pointer. A void pointer being a pointer to anything.
ObjectiveC is then kind of a pure C a level deeper. I will not check exact transformation but since C has no methods this is all done with functions or even pointers to functions. So somewhere down there there should be a function (let's say the name of this class is MyDataClass)
void *myDataClass_data(MyDataClass *self) { return self->_data; } // Or whatever the implementation is
So nothing really interesting is going on under the hood. The whole thing just returns a position in memory without any further information of what should be there. You as a developer must know and interpret it. From C (or ObjectiveC) this is very simply. A few examples:
char *aString = (char *)myDataClass.data; // A pure C string. Expected to be null terminated
int *arrayOfIntegers = (int *)myDataClass.data; // An array of integers
int thirdItem = arrayOfIntegers[2];
MyDataClass *nextItem = (MyDataClass *)myDataClass.data; // A pointer to another instance
for(MyDataClass *iterator = myDataClass; iterator != nil; iterator = (MyDataClass *)iterator.data) {}
I hope you get the picture. The point is that C and then also ObjectiveC are very unsafe when it comes to data types. You can basically convert anything into anything however you want it and it will compile. The problem is what will happen in runtime.
When looking at Swift things get much safer and you can not just say something like let integer: Int = myDataClass as Int. You can force cast it and it will crash. Or you can do optional cast and it will return nil.
So once transitioned from C/ObjectiveC you will receive an unsafe mutable raw pointer. That means it got a position in memory witch it has no idea about what it is and how to use it. You may try to convert it to anything you want but it is unsafe as it will ignore all type checking. It is mutable probably because data it holds may be changed at any given time by any system. It is raw as it holds no additional information (like it's a string). And it's a pointer because it only points to a position in memory.
(All the snippets are symbolical to explain what goes on under the hood. Please do not take them literal)

Is reference counting the same as ownership counting?

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.

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.

Writing struct into NSMutableArray

I have a game object which processed in two completely different places. In Contact Listener i check some conditions and if they occur i must save one or more portions of complex data. So i decided to use struct. For example:
struct SomeStruct
{
int value1;
int value2;
CGPoint value3;
b2Vec2 value4;
};
typedef SomeStruct SomeStruct;
In Game Scene i go through all game objects and if its the stack/array not empty, do some stuff and wipe it.
In Contact Listener it repeats from the beginning.
I must use this architecture because of strict order of execution (method must be called after other methods).
I suspect that i need something like vector or NSMutableArray (i think it will not work with struct), so vector may the the only way.
But don't understand how to achieve it. May you help me with some code/pseudocode or link to the book/article where i can found a solution?
Cocoa provides NSValue class for that purpose:
This creates an object that you can add to NSMutableArray:
NSValue *someObj = [NSValue valueWithBytes:&myStruct objCType:#encode(SomeStruct)];
You can use [someObj pointerValue] to access a void* representing the address of the structure that you put in NSValue.
There is a lot of solutions for this problem.
Don't use struct. An obj-c class is practically the same thing as a struct.
Use CFArray (CFArrayCreateMutable) and put it there as a pointer.
Use a C++ class with STL vector.
Use a C array (SomeStruct[]) and increase its length when you need it.
Use a classic implementation of a stack, with a linked list (every struct has a pointer to the next value).

Objective-C classes, pointers to primitive types, etc

I'll cut a really long story short and give an example of my problem.
Given a class that has a pointer to a primitive type as a property:
#interface ClassOne : NSObject
{
int* aNumber
}
#property int* aNumber;
The class is instantiated, and aNumber is allocated and assigned a value, accordingly:
ClassOne* bob = [[ClassOne alloc] init];
bob.aNumber = malloc(sizeof(int));
*bob.aNumber = 5;
It is then passed, by reference, to assign the aNumber value of a seperate instance of this type of class, accordingly:
ClassOne* fred = [[ClassOne alloc] init];
fred.aNumber = bob.aNumber;
Fred's aNumber pointer is then freed, reallocated, and assigned a new value, for example 7.
Now, the problem I'm having;
Since Fred has been assigned the same pointer that Bob had, I would expect that Bob's aNumber will now have a value of 7. It doesn't, because for some reason it's pointer was freed, but not reassigned (it is still pointing to the same address it was first allocated which is now freed).
Fred's pointer, however, has the allocated value 7 in a different memory location.
Why is it behaving like this? What am I minsunderstanding? How can I make it work like C++ does?
Edit:
Right, a fresh morning and I can see I gave a really bad, 5pm syndrome example.
What I'm trying to do is more like this:
#interface classOne : NSObject
{
int* numA;
}
#property int* numA;
#implementation...etc
numA is alloced and assigned a value. Later on, in a seperate thread (with necessary locks etc), this is done:
int* numB= malloc(sizeof(int));
*numB = 5;
free(RefToClassOne.numA);
RefToClassOne.numA = numB;
numA does get freed, but does not get assigned the value that numB is pointing to, which is the behaviour I would like.
Part of the longer story is that it is the vertex count for part of a vertex buffer that is passed into openGL. I realise that it shouldn't be a pointer, but the float* buffer for the coordinates is dealt with in the same way and needs to be of variable size, so I want to fix this to solve that problem also.
What you are misunderstanding is that (a) you cannot pass things by reference in Objective-C, and (b) even if you could, it wouldn't help you here.
Objective-C only allows you to pass things by value. Sometimes, as in the case of objects or pointers, the value you are passing is itself a reference, but it's being treated as a value. C++-style transparent references don't exist.
But suppose that we had them. How would that help in this case? The aNumber instance variable is still of type int*; when you assign to it (as in fred.aNumber = bob.aNumber), you must create a copy. At this point, it doesn't matter what was passed by reference, and nor does it matter that things are instance variables. Your code is effectively the same as
int* bobNumber;
int* fredNumber;
bobNumber = malloc(sizeof(int));
*bobNumber = 5;
fredNumber = bobNumber;
Here, bobNumber and fredNumber are different variables—they have different names, live at different locations in memory, etc.—that happen to have the same value. Now, the value they have is a reference to another location in memory, so they are equivalent references. However, what happens if we change one of them?
free(fredNumber);
fredNumber = malloc(sizeof(int));
*fredNumber = 7;
Since function arguments are passed by value, free can't do anything to fredNumber itself; it can only operate on fredNumber's value, freeing the referenced memory. Since this is the same as bobNumber's value, we see this effect if we try to dereference bobNumber. Next, we assign a value to fredNumber. Since fredNumber and bobNumber live at different locations in memory, this assignment naturally does nothing to bobNumber. At this point, fredNumber != bobNumber, so naturally when we assign 7 to *fredNumber, nothing happens to *bobNumber (which is invalid anyway, having just been freed).
Note that your comment about "making it work like C++ does" is strange; C++, like I said, doesn't work this way either. If you really wanted to make this work in C++, you would have to have a reference instance variable
class ClassTwo {
public:
int*& aNumber;
ClassTwo(int*& an) : aNumber(an) { }
};
Note that an needs to be passed by reference; I originally tried to do it without that, and then a copy was created in the constructor, producing the same old set of problems.
Now, whether or not we pass bob by reference, it will still have the same aNumber reference, so we can construct something like
int* shared;
ClassTwo bob(shared);
bob.aNumber = new int(5);
ClassTwo fred(bob.aNumber);
delete fred.aNumber;
fred.aNumber = new int(7);
And everything will work like you expect. However, this may well not be a good idea. For one reason why, note the shared variable—references need to be able to reference something. And this can produce problems: if the object being reference goes out of scope, the behavior of the reference is undefined.
If you set both to point to the same object then when you free the object you are effectively removing what both are pointing to so both pointers become invalid. In order to reassign you need to repeat the same procedure by setting both pointers to point to the same new object.
Destroying an object will not automatically update all pointers that point to it since the pointers are independent from each other and don't know anything about each other.
You are better off by creating a clone from the original instead of sharing the object in question so that each 'aNumber' points to its own copy.
I guess what you are after is like in C++ you write
fred = bob;
where fred creates a copy of bob
in that case you would need some kind of clone function in your class.
EDIT: rephrased
Well, as far as I can see your code is doing exactly what you are telling it to.
Using a pointer to an int isn't the most compatible way of handling a value; you will need to call free on it appropriately, and it would strike me as far simpler to use a NSValue object if you just want to pass the value between objects.
This works the same way in C++. Here's an equivalent example:
class Bob {
public:
int *aNumber;
};
void wontWork() {
Bob bob, fred;
bob.aNumber = new int;
*bob.aNumber = 5;
fred.aNumber = bob.aNumber;
delete fred.aNumber;
fred.aNumber = new int;
*fred.aNumber = 7;
cout << *bob.aNumber << *fred.aNumber << endl;
}
Do you expect *bob.aNumber to be 7 here? When you did delete fred.aNumber, that freed the memory that both bob and fred pointed to. Then you reassigned fred to point to new memory, but you did not reassign bob, so it's just a dangling pointer. So there's nothing that would cause bob to be 7. Remember, pointers are just plain value types like ints. There's no magic that causes two pointers pointing to the same address to sync up with each other.