Newbie. Custom class - objective-c

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.

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.

Objective C Convenience Method Use

I am tring to understand convenience methods.
IF I have a sqlite database containing store details and am returning these store details in a FMResultSet. I am thinking that to create an array of these store details as Store objects, that the best way would be create an object of type Store in one go in a convenience method and add to array.
The Class I have created is as below with convenience method
#interface StoreDetails : NSObject
#property (nonatomic, strong) NSString *storeName;
etc etc etc
+ (instancetype)storeWithStoreName:(NSString *)storeName
TelephoneNumber:(NSString *)
telephoneNumber: etc .......
My ResultSet loop would be as below?
NSMutableArray *Stores = [[NSMutableArray alloc] init];
while ([rs next]) {
Store *store =
[Store storeDetailsWithStoreName:[rs stringForColumn:#"storename"]
telephoneNumber:[rs stringForColumn:#"TelephoneNo"]];
[Stores addObject:store];
}
Is my thinking correct as above is is it better to go as below.
NSMutableArray *Stores = [[NSMutableArray alloc] init];
while ([rs next]) {
Store *store = [Store alloc] init];
store.storeName = [rs stringForColumn:#"storename"];
store.telephoneNumber = [rs stringForColumn:#"TelephoneNo"];
[Stores addObject:store];
}
All I am trying trying to understand is why you would use one over the other in noob speak, thankyou.
I think you have a good approach: initializing your Store object in a method of the Store class.
The storeDetailsWithStoreName:... method you have defined is a good example of what Apple calls a factory method (assuming you aren't doing anything weird in its implementation). It's a quite common pattern; Foundation has all sorts of examples: arrayWithCapacity:, numberWithInt:, etc.
With ARC, the simplest examples of these factory methods are nearly identical to a corresponding alloc/init expression, since the developer no longer has to think about autoreleasing objects. But there are still plenty of uses for factory methods, e.g. special instantiation patterns such as singleton or flyweight, including a small amount of common conversion or formatting code for convenience, implementing class clusters, etc. And there's the simple convenience of not having an extra set of brackets and less indentation.
The instancetype keyword is a good choice. This allows you to send the same message to a subclass of Store, with the expectation that the method will instantiate an object of the subclass using the same init method, like this:
+ (instancetype)storeWithStoreName:(NSString *)storeName
telephoneNumber:(NSString *)
...
{
return [[self alloc] initWithStoreName:...];
}
In the code above, as it's a class method, the self in [self alloc] is the Class object (either Store or a subclass of Store) rather than a specific instance of Store. This is what allows creating an instance of the correct class at runtime, depending on whether you call [Store storeWithStoreName:...] or [MoreSpecificStoreSubType storeWithStoreName:...].
The alternative to a factory method, or compliment to it really, is to declare a custom init method in your Store class:
- (id)initWithStoreName:(NSString *)storeName
telephoneNumber:(NSString *)telephoneNumber ...
…and use that directly inside your loop, instead of a factory method. Again, with ARC, not much of a difference between the two unless there's extra work you want to do in the factory method. You can have multiple variants of the init method; the standard practice is for all of them to call the most detailed init method, which is called the designated initializer.
I would recommend taking the time to read the Apple documentation pages on standards for class design (I linked to some of these pages above). Since there are a lot of this is based more on convention rather than language design restrictions, it's important to know all about the patterns and best practices for good design and proper behavior of special methods.

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 - determine class type at runtime

In the interface I have this:
Animal* myPet;
At runtime I may want myPet to be a cat or a dog, which are subclasses of Animal:
id newPet;
if(someCondition) {
newPet = [[Cat alloc] initWithNibName:#"Cat" bundle:nil];
} else {
newPet = [[Dog alloc] initWithNibName:#"Dog" bundle:nil];
}
self.myPet = newPet;
Obviously this is incorrect, but I hope it's enough to show what I'm trying to do. What is the best practice for doing this?
isKindOfClass is your friend:
[newPet isKindOfClass:Dog.class] == NO
Strongly type newPet as Animal * instead of id. id can hold a reference to an instance of any class, but properties cannot be used with it (the dot syntax requires a strongly typed lvalue.) Since both Cat and Dog inherit from Animal, this will be perfectly correct and valid.
If you're using two classes that don't share a common ancestor (past NSObject), then you should take a step back and rethink your design--why would instances of those two classes need to occupy the same variable?
NSString *className = #"Cat";
Animal *myPet = [[NSClassFromString(className) alloc] init];
It's unclear what you are after, but if you want to create an instance of a class named by a string, this should do it.
For anyone arriving from Google based on the title: "Determine class type at runtime", here are some useful things to know:
You can call the class method on an NSObject* at run time to get a reference to its class.
[myObject class];
Take a look at these methods too:
isKindOfClass: - check if an object belongs to a class anywhere in its hierarchy.
isMemberOfClass: - check if an object belongs to a specific class.

How can I pass a class name as an argument to an object factory in cocoa?

I am working on an object factory to keep track of a small collection of objects. The objects can be of different types, but they will all respond to createInstance and reset. The objects can not be derived from a common base class because some of them will have to derive from built-in cocoa classes like NSView and NSWindowController.
I would like to be able to create instances of any suitable object by simply passing the desired classname to my factory as follows:
myClass * variable = [factory makeObjectOfClass:myClass];
The makeObjectOfClass: method would look something like this:
- (id)makeObjectOfClass:(CLASSNAME)className
{
assert([className instancesRespondToSelector:#selector(reset)]);
id newInstance = [className createInstance];
[managedObjects addObject:newInstance];
return newInstance;
}
Is there a way to pass a class name to a method, as I have done with the (CLASSNAME)className argument to makeObjectOfClass: above?
For the sake of completeness, here is why I want to manage all of the objects. I want to be able to reset the complete set of objects in one shot, by calling [factory reset];.
- (void)reset
{
[managedObjects makeObjectsPerformSelector:#selector(reset)];
}
You can convert a string to a class using the function: NSClassFromString
Class classFromString = NSClassFromString(#"MyClass");
In your case though, you'd be better off using the Class objects directly.
MyClass * variable = [factory makeObjectOfClass:[MyClass class]];
- (id)makeObjectOfClass:(Class)aClass
{
assert([aClass instancesRespondToSelector:#selector(reset)]);
id newInstance = [aClass createInstance];
[managedObjects addObject:newInstance];
return newInstance;
}
I have right a better tutorial on that , please checkout
https://appengineer.in/2014/03/13/send-class-name-as-a-argument-in-ios/
It's pretty easy to dynamically specify a class, in fact you can just reference it by it's name:
id string = [[NSClassFromString(#"NSString") alloc] initWithString:#"Hello!"];
NSLog( #"%#", string );
One other tip, I would avoid using the nomenclature 'managed object' since most other Cocoa programmers will read that as NSManagedObject, from Core Data. You may also find it easier to use a global NSNotification (that all your reset-able objects subscribe to) instead of managing a collection of different types of objects, but you're more informed to make that decision than I am.
The bit of the answer missing from the other answers is that you could define a #protocol containing your +createInstance and +reset methods.
It sounds like you want something like:
- (id)makeObjectOfClassNamed:(NSString *)className
{
Class klass = NSClassFromString(className);
assert([klass instancesRespondToSelector:#selector(reset)]);
id newInstance = [klass createInstance];
[managedObjects addObject:newInstance];
return newInstance;
}
This would assume a class method named +createInstance. Or you could just use [[klass alloc] init].
To call it:
MyClass *variable = [factory makeObjectOfClassNamed:#"MyClass"];
Depending on what you're trying to do, it might be better to pass around class objects than strings, e.g.:
MyClass *variable = [factory makeObjectOfClass:[MyClass class]];