Creation of an Objects - objective-c

Car *myCar = [[Car alloc] init];
creates a new Car object with the name myCar. But if it is:
Car *myCar = [[DifferentCar alloc] init];
What will be created? I know that [[Xx alloc] init]; is for creating a new object, but what Xx does there?

creates a new Car object with the name myCar
That's not quite right. It should be "creates a new Car object, and assigns it to a variable called myCar".
But if it is: Car *myCar = [[DifferentCar alloc] init]; What will be created?
I am assuming that DifferentCar is a subclass of Car. An instance of DifferentCar will be created, and assigned to a variable called myCar. The static type of that variable would be Car, but its runtime type would be DifferentCar (or one of its subclasses, if the implementation chooses to make a replacement).
what Xx does there?
In the call above Xx determines the type of object to which the alloc message is going to be sent, ultimately deciding the type of the object being created. Note that since you are calling init right away, the object returned from the call may differ from the object being sent into the call.

Related

Newbie. Custom class

CustomClass *variableName = [[CustomClass alloc] init];
variableName.propertyName = #"Some text";
Could anyone explain this code step by step in human language?
Why if I want to send data to a property in CustomClass I am accessing it throught varibaleName.propertyName , but not through CustomClass.propertyName.
I can not understand it.
If I want to send some data to a varibale in CustomClass wouldn't it be logically to show the path to that property = CustomClass.propertyName = #"Some text"; ?
*variableName - what is it for?
I am confused.
There seems to be some confusion on the difference between an instance and a class. It's generally better to try and link complex ideas like this to real-world examples.
A Class could, for example, be Cars. Thus, you have a Car class. It will include information shared by all Cars. For example, instead of having propertyName it could have a "model" name. To access data about any given car you must first create it. That is what you do in the first line: CustomClass *variableName = [[CustomClass alloc] init];
In our example, we would write Car *myCar = [[Car alloc] init]; which creates a new Car object that we call myCar. Then, you can say myCar.model = "Civic". We do not want to make all cars be a "Civic", but specifically the myCar that we created.
Do not be confused between a Class, which describes a general kind of object, and an Instance, which is the object itself.
Hopefully you now understand the last part of your question:
*variableName - what is it for?
This means that you have a reference to an instance of your CustomClass which is called variableName. In our example, this is myCar which you can then manipulate or change.
You access variableName.propertyName instead of CustomClass.propertyName because variableName is an instance of the class, while CustomClass is the class itself, not the object that you use.
For instance, you have 2 CustomClass objects, lets say variable1 and variable2. variable1.propertyName will be different from variable2.propertyName because they are different instances of the class, not the class itself.

Copying some data of an NSManagedObject to another

I have an NSManagedObject subclass (let's call it) Car with 2 properties of type NSNumber: speed and fuel.
If I have an instance of the class Car and I copy some values to a new instance, are these values connected or are just copied like using the method copy?
Here the code with my doubt:
// The object ferrari was previously obtained from fetch request
Car *lotus = [NSEntityDescription insertNewObjectForEntityForName:#"Repetition"
inManagedObjectContext:self.managedObjectContext];
// solution 1
lotus.speed = ferrari.speed;
lotus.fuel = ferrari.fuel;
// solution 2
lotus.speed = [ferrari.speed copy];
lotus.fuel = [ferrari.fuel copy];
Giving that I want to be sure that the two object are independent, so changing properties or lotus doesn't have to change properties of ferrari can I just use the solution 1?
NSNumber objects are immutable. If you assign
lotus.speed = ferrari.speed;
then both attributes point to the same NSNumber object, but you cannot change
that object. You can only assign a new object:
ferrari.speed = #(454);
but that will not change the value of lotus.speed. So you don't need to copy the
object. The same is true for NSString attributes.

Reassigning an object with ARC

If I've created an NSArray in the init of an object.
Then later on I want to recreate a new NSArray to the same property should I set the old one to nil first?
i.e.
is it ok to just go...
self.arrayProperty = [[NSArray alloc] init];
or should I do...
self.arrayProperty = nil;
self.arrayProperty = [[NSArray alloc] init];
(I'm just using an array for the sake of this example but it's a general questions about properties).
If it makes any difference, it's a strong property.
The first approach is fine, you don't need to set it explicitly to nil before assigning a new object, since the setter releases the backing object of the property before retaining and assigning the new one. Just what you would do under MRC (except that here you don't autorelease the object).
It's just the same, as with ARC an object dies when there are no more references to it. The only difference is that in the second code you're doing a useless extra operation.

Objective-C - Initializing an already initialized object?

What happens if I call [alloc] init] on an object which already was initialized and alloc'ed?
In my particular case I have an NSMutableArray which I initialize in superclass Parent using NSMutableArray* someArray = [NSMutableArray alloc] init];
In subclass Child I need to insert an object in someArray but at a specific index, for example 3.
So if the array has no items, or if it has less items than the index I'm trying to insert at (array has 4 items, and I want to insert at index 10) it will crash.
What would happen if I initialized someArray again in Child class? Would the pointer stored in someArray be replaced with the new one I'm initializing and the "old" one would just leak?
EDIT:
Sorry, my terminology was a bit off. I don't mean doing [someObject alloc], but doing someObject = [SomeClass alloc] init]; where someObject had previoulsy been initialized with an instance of SomeClass
Just for clarity when you say "What happens if I call [alloc] init] on an object..." your terminology is wrong.
The following line:
NSMutableArray* someArray = [[NSMutableArray alloc] init];
Reads in English:
"Send the alloc message to the NSMutableArray class object, then send the init message to the object returned from the first message, then store the object returned from init into the pointer variable named someArray."
I say that to emphasize the fact that you're not "calling alloc/init" on an existing object, you're making a new object, and storing a reference to this new object over the reference you had to the previous object. Since you no longer have a reference to that previous object, you've lost the ability to properly release its memory, so yes, you'll leak it.
correct, it will leak. Use NSMutableArray insertObject:atIndex‎:
There are a couple of ways that come to mind to do what I think you want. A sort of clumsy one is to put as many [NSNull null] objects into the array as you need so that it's filled up to the spot where you need to add the new object. Then you would replace an existing NSNull if you were storing your own object.
Probably a better approach is to use a dictionary instead of an array and turn your index value into a key.

Obj-C - Calling & setting values on ivars & instance methods

I don´t understand what I might be doing wrong here since I am following an instruction book - on setting the value calling a method of an class. I have #imported it, and everything should be fine. But Xcode complains: no know class method selector for "setWeightInKilos and "setHeightInMeters". These instance methods are implemented in the "Person" class so I do not know why this happens.
Person *aPerson = [[Person alloc] init];
[Person setWeightInKilos:96];
[Person setHeightInMeters:1.8];
float bmi = [Person bodyMassIndex];
These are instance methods, not class methods. Therefore you should use the name of the variable aPerson to invoke them on the instance, rather than the name of the class Person:
Person *aPerson = [[Person alloc] init];
[aPerson setWeightInKilos:96];
[aPerson setHeightInMeters:1.8];
float bmi = [aPerson bodyMassIndex];
In general, all methods declared with a - in front take a variable with an instance of that class; methods declared with a + take the class name.
There is also an alternative syntax that you can use if heightInMeters and weightInKilos are declared as properties: you can write
aPerson.weightInKilos = 96;
aPerson.heightInMeters = 1.8;
This is only a different syntax for the same thing, though; the setter methods will be invoked in both cases.
In Objective C, there are two types of methods. Class methods, which do not act on an object, but instead usually perform some task related to that TYPE of object. For example, there are built in methods to test for network connections, device capabilities, etc. These are always denoted with a "+" sign, and cannot be called on instances of objects, only the class itself.
The other type, instance methods, are MUCH more common, and act on objects that you instantiate or create yourself. These are the methods that you write in the implementation file with a "-" prefix. They are things like getters, setters, or methods that you have written yourself.
In your case, you need to call these setter methods on the instance of your Person object, not the Person class itself. It doesnt make sense to set the height or weight of the entire class (nor is it possible), since every object will need to have its own unique height and weight.
You need to call:
Person *aPerson = [[Person alloc] init];
[aPerson setWeightInKilos:96];
[aPerson setHeightInMeters:1.8];
float bmi = [aPerson bodyMassIndex];
It looks like you want to set the instance variables called weight and height. So to fix it, do this:
Person *aPerson = [[Person alloc] init];
[aPerson setWeightInKilos:96];
[aPerson setHeightInMeters:1.8];