I have a few questions about this code:
#import "ViewController.h"
#interface ViewController ()
#property (copy, nonatomic) NSArray *myArray;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.myArray= #[#"one", #"two", #"three", #"four"];
}
I know the self keyword means that's method will be sent to the receiver of that message, and I know when and how to use it if i was creating a simple command utility code, but when learning about creating an iPhone app and using the storyboard every time I see the self keyword it confuses me, I don't know which object is the receiver
2nd question, I know that #[#"object", #"object"];is quick way to create an NSArray object, but "myArray" is a property not an NSArray object. please explain, thank you.
myArray is. The name of a property, as you say. By default, the compiler will create an instance variable called _myArray that's used by that property. In any case, because you've declared the property to be of type NSArray * (and not readonly) you can assign an array to it.
The self keyword is simply a pointer to the "current" object, some instance of the class that you're writing code for when you type "self". If you assign something to self.myArray, the class in which you make that assignment needs to have a myArray property. In your code example, self is a pointer to the particular instance of ViewController that just loaded its view. None of that changes when you're writing an iPhone apportion using a storyboard. self is always the object receiving the method in which self is used. (Note: when used in a class method, i.e. one that starts with +, the object receiving the method is the class itself, not an instance of the class. Don't worry about this if it sounds confusing -- it doesn't come up all that often.)
If you find an expression like self.myArray confusing, it may help to know that property syntax is just shorthand for a method call. Also, self in an expression like that isn't special at all. The syntax is foo.bar where foo can any object pointer (including self) and bar can be any property of the object pointed to by foo. The expression translates directly to either [foo bar] or [foo setBar:...], depending on whether you're reading or assigning a value to the property. So,
self.myArray = #[a, b, c];
means exactly the same as:
[self setMyArray:#[a, b, c]];
self always corresponds to the self class. So every instance of a class will have its own self.
In your case myArray is a property of Class ViewController. Here you can refer to the property by using self.myArray or _myArray.
In the following statement you are creating an array with four strings and adding it to myArray.
self.myArray= #[#"one", #"two", #"three", #"four"];
Your wordings in the question :
I know the self keyword means thats method will be sent to the
receiver of that message
is valid for a method call where you use it as :
[self aMethod];
Even in this you are calling a method which is a part of the class. If you call any method which is not of the current(self) class then you call it by using that class' object name as:
SomeClass *someClassObject = ...
[someClassObject itsMethod];
"self" is a pointer to object to which the method belongs. In your case you may have many instances of ViewController and each of them can call viewDidLoad and in that method "self" is the pointer to the instance itself. To look at it from the C perspective you could create a method using pointer to function where you would also send own pointer to the function called "self", for instance void foo(MyClass *self); to call it then myClassInstance->foo(myClassInstance); this procedure kind of simulates methods but you always need to send instance pointer as well (self). So there should be no confusion as to what "self" is except it is more commonly known by "this" keyword. It is just a reference to the object on which the method is being called.
The property is just a convenience of usually 2 methods called getter and setter. When creating a property #property NSArray *myArray you will actually generate a pointer usually NSArray *_myArray; then a getter:
- (NSArray *)myArray {
return _myArray;
}
And a setter
- (void)setMyArray:(NSArray *)myArray {
_myArray = myArray;
}
How getters and setters are created depends on property attributes (strong, weak, readonly...). You may even override any of these methods or both. So as you stated "but "myArray" is a property not an NSArray object" a property can have truly any type.
Related
I notice that a object pass between two view controllers has the same address in those two controllers. And if I change the value in controller B, the value of object in controller A is changed automatically.
That inspire me to consider the object is a singelton..For singelton design pattern, the advantage is using a global valuable to saving the system resource and keep the consistency of the object.What I am thinking is right? Is there any difference?
An object passed between two view controller can be the same object if
you use strong property.It also can be two different objects if
you use copy property.
If you use a singleton.It will be the same instance of one
class.When using singleton,you should be carefully manage the life
circle of it.
It is about design.
When using object pass between viewControllers,only the two viewControllers can access the object.
But,when using singleton,every place of your application can access the instance.
The Singleton design pattern ensures that only one instance exists for a given class and that there’s a global access point to that instance. It usually uses lazy loading to create the single instance when it’s needed the first time.
Apple uses this approach a lot. For example: [NSUserDefaults
standardUserDefaults], [UIApplication sharedApplication], [UIScreen
mainScreen], [NSFileManager defaultManager] all return a Singleton
object.
For more about Singleton design pattern go through the Link
In Objective-C or swift all what you call as "Object" is a pointer to object. It is not a object in C++ terms, it is a pointer in the C++ terms.
Because variable it is pointer, then you use a variable to call functions, the pointer is copied but not a pointed object.
But in Objective-C exist a C objects (structures (CGSize for example) and simple variables (int, float ...)), these variables will be copied if you will use them to call functions.
About properties: property it is methods (set and get, if property not readonly).
If property have parameter strong (retain):
#property (strong) NSObject* a
then it property can be implemented like a function:
- (void)setA:(NSObject*)a
{
_a = a;//or [_a release]; _a = [a retain]; if no ARC
}
If property have parameter copy:
#property (copy) NSObject* a
then it property can be implemented like a function:
- (void)setA:(NSObject*)a
{
_a = [a copy];//or [_a release]; _a = [a copy]; if no ARC
}
Property it is a method!
You can create many instances of any object classes:
NSObject* a = [[NSObject alloc] init];
NSObject* b = [[NSObject alloc] init];
a and b its pointers to different objects in a memory.
But if you not allocate b object:
NSObject* a = [[NSObject alloc] init];
NSObject* b = a;
a and b its pointers to one object in the memory.
About singleton: the singleton pattern is a design pattern that restricts the instantiation of a class to one object.
I have created one class which is subclass of NSObject(nsme as GroupClass).In that class I have created one property which is belonging from 'id' ,like
#property(nonatomic,retain)id myObj;
Now I am standing on way where I have one mutable array,that array contains instances of my GroupClass.so I am getting one copy in similar way
GroupClass* objG=[array objectAtIndex:i];
now I want one another copy of objG.I searched .And I found NSCopying Protocol.So I added as delegate NSCopying to GroupClass and also added copyWithZone method.Here it is
-(id)copyWithZone:(NSZone *)zone
{
GroupClass *copy = [[[self class] allocWithZone: zone] init];
copy.myObj=[myObj copyWithZone: zone];
return copy;
}
Here I need deep copy.but it is always crashing after allocation line.Please help me.Thanking You.
Not all NSObject subclasses adopt the NSCopying protocol. The problem sounds like you are sending this message to an object which doesn't recognise it.
It doesn't matter that your GroupClass adopts NSCopying, that is not the problem. You are calling copyWithZone: on myObj, whatever that is.
This line of code:
copy.myObj=[myObj copyWithZone: zone];
Is almost certainly what is causing the crash.
EDIT
Not knowing what myObj is, I would recommend that if it is possible, and isn't a bad idea, that you subclass whatever the class is.
If it is a UIView for example, I would subclass it like so:
#class JVView : UIView <NSCopying>
I would then implement the copyWithZone: method appropriately, copying any of the properties of the instance that you feel are necessary.
Well I'm just confused when the lazy instantiation should be used.
I understand the basic concept of lazy instantiation though.
" I understand that all properties start out as nil in Objective-C and that sending a message to nil does nothing, therefore you must initialize using [[Class alloc] init]; before sending a message to a newly created property. "(Lazy instantiation in Objective-C/ iPhone development)
m.file:
#property (strong, nonatomic) NSMutableArray *cards;
- (NSMutableArray *)cards
{
if (!_cards) _cards = [[NSMutableArray alloc] init];
return _cards;
}
- (void)addCard:(Card *)card atTop:(BOOL)atTop
{
if (atTop) {
[self.cards insertObject:card atIndex:0];
} else {
[self.cards addObject:card];
} }
Well, what I really don't get is when I'm supposed to use this type of instantiation?
Mostly I see the code like this:
h.file:
#interface Card : NSObject
#property (strong, nonatomic) NSString *contents;
m.file:
if([card.contents isEqualToString:self.contents]){
score = 1;
}
*This might be a stupid question but I'm really confused. I'm new here, Thanks.
There is no reason to use Lazy Instantiation/Lazy Initialization if you find it confusing; simply initialize your instance variables/properties in the class init methods and don't worry about it.
As the object is created as a side-effect of calling the getter method, it's not immediately obvious that it is being created at all, so one alternative, which would also mean you can use the default compiler-generate getter method, is to explicitly check for it in addCard:
- (void)addCard:(Card *)card
atTop:(BOOL)atTop
{
if (!self.cards)
self.cards = [NSMutableArray new];
if (atTop) {
[self.cards insertObject:card atIndex:0];
} else {
[self.cards addObject:card];
}
}
(and removing the user-supplied getter method)
However the net-effect is the same as the code you posted, with the exception that self.cards will return nil until addCard is called, however I doubt this will cause a problem.
When using dot notation to access your instance variables, you are calling your getter method for that given property. Therefore, by using dot notation and lazy instantiation, your getter will always assert that a property is not nil before you send it a message. Therefore, code such as
[self.cards insertObject:card atIndex:0];
will actually call the getter at self.cards; if you use dot notation on your objects and program the getters accordingly, you will always ensure that your instance variables are allocated and initialized, while simultaneously cleaning up your init method for code that is much more important.
Lazy instantiation is a common practice among Objective-C programmers; I suggest getting into the flow of the convention.
EDIT: thanks for Raphael mentioning this in a comment previously.
Lazy instantiation is a performance enhancement in certain types of scenarios. One example would be a class that has a very expensive user facing UI string.
If you create many of instances of that class but only a very small subset of those instances will be shown in your UI, you waste a lot of CPU resources creating a very expensive UI string that rarely will be used.
When I have code like the following:
self = [super init]
does self point to super? If so, why would you want this? if my instance object has the variable "someVal", I won't be able to get to it by doing [self someVal]. correct?
How then would I get to the instance variable's using self when self points to super?
does self point to super?
It's really the other way around. super is really the same as self, except that it tells the compiler to start looking for method implementations starting with the superclass rather than the class itself. You can check this by logging the value of super and the value of self; you'll find that they both point to the same address.
When you create an object, you do this:
Foo *f = [[Foo alloc] init];
The alloc allocates the memory that will become the object you're creating, but until that memory is initialized it's just a chunk of memory -- not a valid object. If Foo is a subclass of Bar and Bar is a subclass of NSObject, then by convention Foo's initializer will call Bar's, and Bar's will call NSObject's, so that the initialization proceeds in order: first the memory is initialized by NSObjects' -init, and Bar's init receives the returned value and assigns it to self. It then proceeds to do any Bar-specific initialization, and returns self. Foo's -init then assigns the returned value to self again and finally does any Foo-specific initialization.
All that assigning to self might seem both redundant and confusing. It's really just a convention, but the purpose is to allow the superclass's initializer to return some object other than the one that was allocated, including nil. So, for example, if the initialization of Bar failed for some reason, -[Bar init] could return nil. The possibility that nil might be returned from [super init] is the reason we put the self = [super init] assignment inside a conditional: if the assigned value is nil, the initialization part is skipped and nil is returned. It's also possible that -[Bar init] could return a pointer to an object other than the one that was allocated, such as when an object similar to the one being created already exists and can be reused.
Most of the time, the pointer you get back from -init will be the same one that you got from +alloc, so you could write this:
Foo *f = [Foo alloc];
[f init];
If you write that, however, you're making an assumption that the initializers of your class and all the classes that it inherits from will always return the same object, and will never return nil. By doing that you're breaking the convention and severely hamstringing yourself and whoever wrote the classes from which Foo inherits -- they'll break your code if they return a different object in a future release of the class. Also, it'll look like you don't know what you're doing.
does self point to super?
This question doesn't make sense in an instance method, since there super is not really a concrete/actual pointer-to-instance, it just indicates that the implementation of the superclass must be called. And since in the case of most objects (except class clusters) all methods return self;, then the answer is no: the actual pointer to the instance doesn't change magically by itself.
For the record: the exception is manifested by class clusters (most Cocoa container classes, for example, NSString, NSArray, etc.). These classes often have an initializer method that returns a different instance than the one that was originally allocated, and of which the class is a concrete subclass of the class of the original self. For example, an implementation of the NSString initializer could be:
#implementation NSString
- (NSString *)init
{
[self release];
self = [[__NSCFString alloc] init];
return self;
}
#end
The reason for this is that optimizing for different types of initialization can be achieved this way.
Self is always pointing to one instance. When you use super you are referencing parent methods not a parent instance.
self means current class' instance.
self = [super init] means self is getting the value returned by [super init].
Could someone share some knowledge on whats best practice / code convention on using #property iVars in init methods or designated initializers?
please see my example:
#interface MyClass ()
#property(nonatomic,strong) nsstring *tempString;
#property(nonatomic,strong) NSMutableArray *arrItems;
#end
#implementation ViewController
- (id)init
{
if (self = [super init]) {
//Is this best practice / correct
_tempString = #"";
_arrItems = [[NSMutableArray alloc] initWithCapacity:0];
...
...
//Or this
self.tempString = #"";
self.arrItems = [[NSMutableArray alloc] initWithCapacity:0];
}
return self;
}
#end
Any advice on why one or the other should be used?
Thanks...
Apple's guidance on this topic is included in the aptly named section Don’t Use Accessor Methods in Initializer Methods and dealloc.
Read this thread: Why shouldn't I use Objective C 2.0 accessors in init/dealloc?
In other words if you are not goiung to use KVO you can use second approach:
//Or this
self.tempString = #"";
self.arrItems = [[NSMutableArray alloc] initWithCapacity:0];
But be care full with alloc-init, don't forget about autorelease.
It's typically better to use property notation when you define it, partly(mostly?) for the reason Jeremy mentioned.
Debugging a particular variable is a whole lot easier when you can set a breakpoint in method setter override and have it apply to ALL code paths that modify the variable.
Another reason is to keep a consistent memory management model, although it is less important since you are using ARC. If you weren't however, and strong was retain, then you would make sure that the object you are setting to the property is autoreleased everywhere you set the property, and not have to deal with releasing the current value if you are directly setting the variable.
Consistency is important for maintenance/readability and debugging, no matter what practices you use.
I prefer the lazy instantiation method for properties.
After you #synthesize you can override your getter to lazily instantiate your property
For Example:
-(NSString *)tempString {
if(!tempString) {
_tempString = #"";
}
return _tempString;
}
and
-(NSMutableArray *)arrItems {
if(!_arrItems) {
_arrItems = [[NSMutableArray alloc] initWithCapacity:0];
}
return _arrItems;
}
If you do want to set your property in the init method, use dot notation self.myProperty so that it uses the defined setter for the property and not the private class method directly.
According to Apple, you should not use accessors in init... or dealloc methods:
You should always access the instance variables directly from within
an initialization method because at the time a property is set, the
rest of the object may not yet be completely initialized. Even if you
don’t provide custom accessor methods or know of any side effects from
within your own class, a future subclass may very well override the
behavior.
Taken from this doc: Encapsulating Data.