Copying some data of an NSManagedObject to another - objective-c

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.

Related

Creation of an Objects

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.

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.

Get only the properties of an object that were declared in the header

I'm looking for a way to access, at runtime, only the properties of an object that were declared in the header file for that class. I was able to retrieve all the properties of an object via the following code:
MyTest *myTestObj = [[MyTest alloc] init];
myTestObj.prop1 = #"prop1";
myTestObj.prop2 = #"prop2";
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
unsigned count;
objc_property_t *properties = class_copyPropertyList([myTestObj class], &count);
for (int i = 0; i < count; i++) {
NSString *key = [NSString stringWithUTF8String:property_getName(properties[i])];
id keyValue = [myTestObj valueForKey:key];
if (keyValue != nil) {
[dict setObject:keyValue forKey:key];
}
}
free(properties);
(see Get an object properties list in Objective-C for more examples)
However, I need a way to limit the properties retrieved to only the ones declared in the .h file.
Basically, I'm looking for a way to access the object's public interface. Any suggestions on how to do this would be greatly appreciated.
I'm trying to save the state of my object in a dictionary so that it can be recreated later. Specifically, I'm trying to save it to the userInfo property of UILocalNotification.
I save the state of the object (in my case a UIViewController) to the userInfo property and create a local notification. When the user opens the app via a notification, I want to recreate the same UIViewController and set its state to what it was at the time the notification was created.
If there is a better way to do this that doesn't involve hardcoding then I'd love to hear some suggestions.
Declaring a property in the header or in a class extension (or category somewhere else) does not change the available runtime information of the property.
I need a way to limit the properties retrieved to only the ones declared in the .h file
There's no way to do that.
After edit:
On the other hand it's a very common pattern to just add a property or method that returns a set of keys to be serialized. You could, for example, make all your model classes implement a method like the following:
+ (NSArray *)persistentKeys
{
return #[ #"name", #"color", #"foo" ];
}
For each object to serialize your serialization code then has to walk the class and superclasses of the object and collect all persistent keys.
What you are trying to do is bizarre. Please have a look at the NSCoding protocol which is designed to do what you want to do. Looking at properties declared in the header file is a totally weird idea. You have no idea whether or not setting the public properties would have the result you want.

Multiple class instances

There's the instance1 and instance2 of the same class (RandomClass).
I want to set the instance1.string as #"instance 1 string" and instance2.string as #"instance2 2 string", and access them differently, but looks like when I set the instance2.string the instance1.string also changes it value. I'm using sharedInstance method;
Something like:
RandomClass *instance1 = [RandomClass sharedInstance];
instance1.string = #"instance 1 string";
RandomClass *instance2 = [RandomClass sharedInstance];
instance2.string = #"instance 2 string";
NSLog(#"%#", instance2.string); // wich results 'instance 2 string'
NSLog(#"%#", instance1.string); // wich results 'instance 2 string'
As you can see, the instance2.string changes the instance1 string value.
Is there any way to create different instances, separately, dealing with the class objects as unique values (accessed by it own instance)?
Your example is not valid because you doesn't have two instances of the same class, you have only one singleton instance. Note that [RandomClass sharedInstance] return always the same instance, you only have two references for it.
The normal way to create instances is
[[RandomClass alloc] init...]
Please don't use the term thread in the context of class and instances, this only makes the problem more confusing.
I believe you should visit some Obj-C tutorials or some OOP tutorials first.
instance1 and instance2 are referencing the same object as [RandomClass sharedInstance]. If you modify any of them, all of the changes will be take affect on the original sharedInstance.
If you want two different objects, you must instantiate two times (if RandomClass provides any initializer method):
RandomClass *instance1 = [[RandomClass alloc] init];
instance1.string = #"instance 1 string";
RandomClass *instance2 = [[RandomClass alloc] init];
instance2.string = #"instance 2 string";
NSLog(#"%#", instance1.string); // wich results 'instance 1 string'
NSLog(#"%#", instance2.string); // wich results 'instance 2 string'
(By the way, RandomClass looks like a Singleton, so there might be no way to instantiate multiple objects.)

Objective C: Request for member XXX in something not a structure or union. (Core Data)

I am hitting this error when implementing core data.
I have created a entity 'FlashCard' with the attribute 'question' and 'answer'. Both the attributes are of NSString type.
After inserting a new object into the NSManaged Object, I tried to set the 2 attributes as seen below.
NSManagedObject *newCard = [NSEntityDescription insertNewObjectForEntityForName:#"FlashCard" inManagedObjectContext:self.managedObjectContext];
newCard.question = thisQuestion;
newCard.answer = thisAnswer;
But when I try to compile the code, I am hitting the error "Request for member 'question' in something is not a structure or union'. I get the same error for newCard.answer line.
Any advise on how to resolve this is greatly appreciated!
Zhen
Your newCard instance should be of type FlashCard not NSManagedObject; otherwise, the compiler won't know that newCard has the properties question and answer.
FlashCard *newCard = (FlashCard *)[NSEntityDescription insertNewObjectForEntityForName:#"FlashCard" inManagedObjectContext:self.managedObjectContext];
newCard.question = thisQuestion;
newCard.answer = thisAnswer;
You've declared newCard as an NSManagedObject, then tried to access properties that NSManagedObject doesn't define.
Core Data gives you the option of using a custom subclass of NSManagedObject to represent entities. If you're doing this then, as others have suggested, you need to declare newCard as an instance of that subclass (in case you're not doing this, you'll have to write the class and declare the properties yourself if you want to use the 'dot' property syntax --- core data doesn't automatically create a subclass of NSManagedObject for each entity type)
Also, you don't have to use your own subclass or write accessors just to access a managed object's attributes and relationships. If you don't need to add any custom logic to FlashCard yet, you can use key value coding on an NSManagedObject instead. This would work fine:
NSManagedObject *newCard = [NSEntityDescription insertNewObjectForEntityForName:#"FlashCard" inManagedObjectContext:self.managedObjectContext];
[newCard setValue: thisQuestion forKey: #"question"];
[newCard setValue: thisAnswer forKey: #"answer"];
#import "FlashCard.h"
Is "FlashCard.h" included at the top of this file?