In the stanford course Paul Hegarty prefers to use lazy instantiation. For instance he makes a private declaration of
#property (strong, nonatomic) (NSArray *)cards
and then he uses the getter to perform an initialization
- (NSArray *) cards
{
if(!_cards) _cards = [[NSArray alloc]init]
return _cards;
}
I'm cool with that. What I don't get though is that at another time Paul declares a public suit for a playingCard being:
#property (strong, nonatomic) NSString *suit;
but in the implementation he doesn't perform this lazy instantiation. So I don't understand where the alloc init of the suit string happens? (suit being a pointer to an NSString - object which ought to get a place in the heap)
#import "PlayingCard.h"
#implementation PlayingCard
#synthesize suit = _suit;
- (void)setSuit:(NSString *)suit
{
if ([#[#"♣︎", #"♠︎", #"♥︎", #"♦︎"]containsObject: suit]) {
_suit = suit;
}
}
- (NSString *)suit
{
return _suit? _suit: #"?";
}
#end
The property is public, so he assumes that it will be set somewhere. When you set this property you can alloc, init and then set it to Playing card instance, for example:
PlayingCard *playingCard = [PlayingCard new];
[playingCard setSuit:#"spade"];
Lazy initialisation is used if property is private (so you can not initialise it outside of the class), but you don't want to initialise it in init method of the class.
When you ask for the cards instance there is no additional information required (i.e. there are no necessary parameters). You just instantiate a PlayingCard and return it.
A suit, on the other hand, could be one of four options, so somebody needs to set that somewhere. Note that this issue is really independent of lazy initialization. It has more to do with the fact that suit expects to be initialized with a user-parameterized value.
Lazy initialization is a way to say, "don't bother creating an instance of this object until I ask for it." But in the case of suit, you don't want to create the string until the user supplies it.
Lazy instantiation is not a panacea but can improve the object instantiation and app responsiveness if you don't spend cycles instantiating ivar objects all at once before you need them. This effect is nothing on a small simple class, but if you have a large set or array of objects, setting them all up completely at once will slow down things at one point.
To be fair the same hit could come later.
Related
This question already has answers here:
Objective-C declared #property attributes (nonatomic, copy, strong, weak)
(4 answers)
Closed 6 years ago.
I was trying to pass a custom object to the next view controller and I encountered this error -[ClassName copyWithZone:] unrecognized selector sent to instance
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"attemptDetails"])
{
ResultsVC *vc = segue.destinationViewController;
vc.selectedEntry = selectedEntry;
}
}
#property (nonatomic, retain) ClassName *selectedEntry; //Why is it retain and not copy?
I'm still very confused with property attributes and why certain types use certain attributes, like NSString uses (nonatomic, copy) and CLLocationCoordinate2D uses (nonatomic, readonly).
Could someone explain or link a reference to me how each property attribute works? Much thanks!
There are lots of descriptions for property attributes explanation,
Reference links,
Objective-C ARC: strong vs retain and weak vs assign
https://stackoverflow.com/a/4511004/4294543
#property and retain, assign, copy, nonatomic in Objective-C
Short & simple my understanding is like,
retain : It's working on the created object, and it just increase the reference count.
Here in your case you have already model class object so not need to copy in the second vc property,you just need to retain it to second vc property.
copy : The value you assigned to property can be copied & used for other purposes too(create shallow copy of object & need when object is mutable & need to release after finish with it).
nonatomic : Thread access is faster but you can't simultaneously access & change your property.
readonly : You can't directly assign the property new value.
Even i have run your case in the my project,
#import "ViewController.h"
#import "TestViewController.h"
#import "CustomClass.h"
#interface ViewController (){
CustomClass *classT;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
classT = [[CustomClass alloc]init];
classT.test = YES;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)btn:(id)sender {
TestViewController * vc = [self.storyboard instantiateViewControllerWithIdentifier:#"TestViewController"];
vc.className = classT;
[self presentViewController:vc animated:YES completion:nil];
}
#end
#import <UIKit/UIKit.h>
#import "CustomClass.h"
#interface TestViewController : UIViewController
#property (nonatomic,retain) CustomClass *className; // Work as i said
//#property (nonatomic,copy) CustomClass *className; // Makes a copy of an object, and returns it with retain count of 1. If you copy an object, you own the copy. This applies to any method that contains the word copy where “copy” refers to the object being returned thats why here you will get crash
#end
I have read couple of good article for memory management. According to rypress
Retain Attribute : The retain attribute is the Manual Retain Release version of strong, and it has the exact same effect: claiming ownership of assigned values. You shouldn’t use this in an Automatic Reference Counted environment.
Copy Attribute : The copy attribute is an alternative to strong. Instead of taking ownership of the existing object, it creates a copy of whatever you assign to the property, then takes ownership of that. Only objects that conform to the NSCopying protocol can use this attribute.
Even I went through some good link of stackoverflow as well. Joshua Nozzi's answer gave good explanation for retain vs copy.
Retain vs. Copy - Declared properties use retain by default (so you can simply omit it altogether) and will manage the object's reference count automatically whether another object is assigned to the property or it's set to nil; Use copy to automatically send the newly-assigned object a -copy message (which will create a copy of the passed object and assign that copy to the property instead - useful (even required) in some situations where the assigned object might be modified after being set as a property of some other object (which would mean that modification/mutation would apply to the property as well).
Also found good example here.
Code :
NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:#"First",#"Second", nil];
NSMutableArray *copiedArray = [array mutableCopy];
NSMutableArray *retainedArray = [array retain];
[retainedArray addObject:#"Retained Third"];
[copiedArray addObject:#"Copied Third"];
NSLog(#"array = %#",array);
NSLog(#"Retained Array = %#",retainedArray);
NSLog(#"Copied Array = %#",copiedArray);
Output :
array = (
First,
Second,
"Retained Third"
)
2013-12-19 17:15:49.380 RetainVsCopy[2876:c07] Retained Array = (
First,
Second,
"Retained Third"
)
2013-12-19 17:15:49.381 RetainVsCopy[2876:c07] Copied Array = (
First,
Second,
"Copied Third"
)
See, both array and Retained Array are having same contents. This is because both are pointing to same memory/instance/object. Where as contents of Copied Array are different. This is because copy created a separate instance.
In Objective C you will find that each class actually has a structure behind it. The properties are shortcuts which create the value in structure, a getter and a setter. For instance:
#interface MyClass
#property id myValue;
#end
Will create:
#interface MyClass {
id _myValue;
}
#property id myValue;
#end
#implementation
- (id)myValue {
return _myValue;
}
- (void)setMyValue:(id)myValue {
_myValue = myValue;
}
#end
Now these flags such as retain and copy add additional logic to the setters and getters. Using copy will actually create a setter as:
- (void)setMyValue:(id)myValue {
_myValue = [myValue copy];
}
Which means that the value must have the copy method implemented. Since your object does not it crashes.
Why to use copy is for safety. This is rarely important for something as strings but it is important for something like an array. So for instance you create a property #property NSArray *myArray; which expects an un-mutable array but the problem is that you can set a mutable array as well: myClassInstance.myArray = [[NSMutableArray alloc] init];. Now 2 modules have the access to the same mutable array. So if the first object starts modifying the array while the other one expects the array to always be the same you may find some issues. For instance MyClass instance may use it as a data source for the table view and at some point the array is mutated but the cells are not added/removed and the table view will cause a crash.
To be honest you can simply leave all of these as default and modify them only when you really need to. The case like above is highly unlikely anyway.
I have a few different viewControllers that need to inherit the same properties, but aren't the same type of viewController. For example, one VC is a regular UIViewController, whereas another one is a UISplitViewController. Is there any way for me to efficiently use inheritance to make sure they all have these certain properties? Or do I just need to give each one their own separate declarations?
You can achieve what you want using a category on UIViewController. You can implement the properties in the category using associated objects.
See Objective-C: Property / instance variable in category for more details.
You could add a category to UIViewController. Since UISplitViewController inherits from UIViewController, it will have all properties and methods as defined in the category as well. However, categories have two limitations:
You can't add backing instance variables. You can create properties, but they can't have instance variables backing them. That means that if you are overriding the getter (and setter, if readwrite), so that it reads (or writes) an already existing property in some way, you're good. If not, you can look at associated objects.
Overriding methods in a category is a no-no. While nothing stops you from doing it, you have undefined behavior if another category overrides that method too. You just don't know which method will get executed. If you need to override methods, subclassing UIViewController would be better. However, UISplitViewController will then not know about these properties, unless you subclass it as well and add those same properties (in which case you're maintaining these properties twice).
I'm not sure what exactly do you need. If you don't want to (or can't) use common superclass with public properties, you can always write protocol. Only difference is that, protocol don't give you common implementation, but force you to write one (so you can be sure it is there, as you asked for).
Why not set up inheritance using a shared base class and set those shared properties in the init?
//MyBaseVC.h
#interface MyBaseVC : UIViewController
#property (nonatomic, strong) NSString *myString;
#end
//VC1.h
#interface VC1 : MyBaseVC
#end
//VC2.h
#interface VC2 : MyBaseVC
#end
-----
//(MyBaseVC.m)
-(id) init {
self = [super init];
if(self){
self.myString = #"Hello world!";
}
return self;
}
// VC1.m
-(id) init {
self = [super init];
NSLog(#"%#", self.myString); // "Hello world!"
return self;
}
// VC2.m
-(id) init {
self = [super init];
NSLog(#"%#", self.myString); // "Hello world!"
return self;
}
At that point, you can directly refer to the property on the subclassed objects:
NSLog(#"%#",myVc1.myString); //"Hello world!"
Otherwise, when you reference the VCs in a more generic fashion, you can always refer to their super class (MyBaseVC) - for example, if you need to pass them as a method parameter.
//-(void)doSomethingWithVC:(MyBaseVC *)vc;
[someObj doSomethingWithVc: vc1];
I've a theoretical doubt about two type of declaration of a mutable object in iOS (and MacOSX I think) with ARC.
What's the difference between a declaration of an NSMutableArray in the Class Extension, like the code below:
#interface MyViewController ()
#property (copy) NSMutableArray* myMutableArray;
#end
//Class implementation
#implementation MyViewController
...
- (void)viewDidLoad
{
_myMutableArray = [#[] mutableCopy];
}
and a declaration of the same array in this way
#interface MyViewController ()
#property (nonatomic, strong) NSMutableArray* myMutableArray;
#end
//Class implementation
#implementation MyViewController
...
- (void)viewDidLoad
{
_myMutableArray = [#[] mutableCopy];
}
Which one is better? I've seen both versions around and apparently both work fine. However I'd like to know which one is the best option.
I know that the "copy" keyword is to use copy for classes that are part of a class cluster that have mutable/immutable pairs. So in this case, it appear to be the right choice. But the use of the "copy" keyword and the "mutableCopy" property (like the first example) seems a duplicate to me. Am I wrong?
Thanks!
The strong property is the one to use. Since its a mutable object (and is declared as such) then you wouldn't want a copy making, since then things like [self.myArray addObject:object] wouldn't work. You'd use copy properties for immutable objects that may have mutable versions passed in (so an NSString would often be a copy property).
The way the arrays are assigned (making a mutable copy of an empty array made using objective-c literals) is pretty clumsy and would be better written as self.myMutableArray = [NSMutableArray array];
Also, don't access the instance variable directly, use the property accessor.
This question already has answers here:
Declaration/definition of variables locations in ObjectiveC?
(4 answers)
Closed 9 years ago.
What is the proper way to work with instance variables (declared on interface), their #property and #synthesize, when working in ARC project? What I now do is following:
SomeClass.h:
#interface SomeClass : NSObject {
NSString *someString;
}
#property(nonatomic, copy) NSString* someString;
and SomeClass.m:
#implementation SomeClass
#synthesize someString;
- (void)someMethod {
self.someString = #"Foobar";
}
The thing is that there are other approaches that works, like using just the #property:
SomeClass.h:
#interface SomeClass : NSObject
#property(nonatomic, copy) NSString* someString;
Accessing the someString without self:
SomeClass.m:
#implementation SomeClass
#synthesize someString;
- (void)someMethod {
someString = #"Foobar";
}
etc. I'm new to Objective-c, I'm used to Java. What is the proper way to work with attributes then? I understand that special cases will have special behavior, but what is the best approach in general? (by general I mean I want to access the variable from the class itself and from "outside" and I want ARC to still work correctly, eg. I don't have to worry about memory leaks)
For simple properties, you don't need the instance variable declaration or the #synthesize. The clang compiler will generate both for you by default. So you could write this in the header:
#interface SomeClass : NSObject
#property (nonatomic, copy) NSString *someString;
#end
And the implementation:
#implementation SomeClass
- (void)someMethod {
self.someString = #"Foobar";
}
#end
Avoid direct instance variable access unless you are in the -init method or overriding the setter. Everywhere else you should use the dot syntax (self.someString). If you do need access to the instance variable, the default synthesize will create an underscore-prefixed ivar, e.g. _someString.
Note that for classes with mutable versions like NSString/NSMutableString and NSArray/NSMutableArray the standard practice is to use a copy property. If you use strong on a string or array, the caller might pass in a mutable version and then mutate it from under you, causing hard-to-find bugs.
Check out this SO post for information about ARC.
(Edited) The "strong" attribute tells ARC to keep an object around until the object with the property is deallocated. You do need the "copy" attribute because an NSString property could have been passed in as an NSMutableString. The "copy" guarantees that the original object will be kept around. Again, I apologize for the incorrect/misleading information I originally had here.
The reason you can access the instance variable someString as well as the property self.someString is that the #synthesize someString line creates an instance variable for the property and creates methods for getting and setting the value of it. However, it is recommended that you use the property instead of directly using the instance variable because by using the instance variable, you cannot let the parent object know that you've changed one of its properties.
I have a project which others have written and I have taken over it, hoping to make the app better.
I encountered one problem:
From one class:
I write _customclass.variable. CustomClass is another class and variable is a property and is of int type. And I get value of the variable in this class, but when I change it to self.customclass.variable, I always get 0. Is there other alternative ways to get value from other class?
(a)
#property (readwrite)int boxSpacing;
(b)
#synthesize boxSpacing;
(c)
- (id)initWithCoder:(NSCoder *)aDecoder {
self.boxSpacing = 10;
}
You asked:
Is there other alternative ways to get value from other class?
The short answer is that using the "getter" is the customary way to get a value from another class. But looking at your problem (admitted, not having enough source code to properly diagnose your issue), I'm guessing that the issue rests in the use of instance variables. But more on that later.
First, let's look at the proper use of declared properties and their instance variables and their accessor methods (the getters and setters). Generally you should set properties using these accessor methods. You can, though, use access a variable from within a class using either the instance variable (and you should not use accessor methods in initializer and dealloc methods). And when using the getter and setter, you can choose whether to use the method invocation (e.g. "[self customObject]") or the dot notation (e.g. "self.customObject").
Let's look at an example. Let's assume you have some simple CustomClass:
#interface CustomClass : NSObject
{
// you don't need to declare the instance variable
//int _boxSpacing;
}
#property (nonatomic) int boxSpacing;
#end
#implementation CustomClass
// In Xcode 4.4 and later, the synthesize statement is optional, and if you
// omit it, it will synthesize the instance variable like this, with the
// leading underscore. While you don't need to use an underscore in your
// instance variable, it has become convention in iOS development and it's
// a good technique to minimize chances that you accidentally use the instance
// variable when you actual intended to use the property's accessor methods
// (the getter and setter).
#synthesize boxSpacing = _boxSpacing;
#end
Now, let's assume that you're going to use this CustomClass from within, for example, your view controller. So, first you declare and instance of this CustomClass:
#interface MyViewController : UIViewController
{
// you do not need this instance variable declaration
// the #synthesize statement will take care of this for you
// CustomClass *_customObject;
}
#property (nonatomic, strong) CustomClass *customObject;
#end
And then let's demonstrate how to use the value property of the CustomClass object customObject from within your view controller:
#implementation MyViewController
// Again, in Xcode 4.4 and later, the synthesize statement is optional, and if you
// omit it, it will synthesize the instance variable like this, with the
// leading underscore
#synthesize customObject = _customObject;
- (void)customClassTest
{
// initialize the object
self.customObject = [[CustomClass alloc] init];
// set the property
self.customObject.boxSpacing = 1;
// finally, let's demonstrate three ways to retrieve the value
NSLog(#"%d", self.customObject.boxSpacing);
NSLog(#"%d", [[self customObject] boxSpacing]);
NSLog(#"%d", _customObject.boxSpacing);
// while we're at it, let's demonstrate other ways to set the property
_customObject.boxSpacing = 2;
// or
[[self customObject] setBoxSpacing:3];
}
Ok, so let's get back to your problem. You say:
I write _customclass.variable. CustomClass is another class and variable is a property and is of int type. And I get value of the variable in this class, but when I change it to self.customclass.variable, I always get 0.
Ok, this can be caused by a couple of different problems, but the most common problem I see is confusion between explicitly declared instance variables and the instance variables created behind the scenes by the #synthesize statement. This is why I always advise that people not explicitly define the instance variables for their declared properties, but rather let the #synthesize statement do that automatically. That way I can't have the sort of problem I'm about to demonstrate.
Consider this innocuous (though incorrect) example:
#interface MyViewController : UIViewController
{
CustomClass *_customObject;
}
#property (nonatomic, strong) CustomClass *customObject;
#end
#implementation MyViewController
#synthesize customObject;
- (void)customClassTestError
{
// initialize the object
self.customObject = [[CustomClass alloc] init];
// this works
self.customObject.boxSpacing = 1;
// this doesn't!
_customObject.boxSpacing = 2;
// when it hits this statement, the value will still be 1!!!
NSLog(#"%d", self.customObject.boxSpacing);
}
Do you see the problem? While I declared an instance variable with the underscore, _customObject, when the compiler hit the #synthesize statement, it created another instance variable, this time without the leading underscore, customObject. Thus, my explicitly declared instance variable never received the init/alloc and therefore is nil and thus any attempts to use it won't work!
Typically we see the converse problem (an explicitly declared instance variable without the underscore and a #synthesize statement of the form #synthesize customObject = _customObject), but hopefully you'll get the idea.
Anyway, this is the most common example of what would cause the behavior you describe. If this isn't what's going on, please provide us a more extensive code sample.
But if you're having problems, I'd always suggest that you check the value of your CustomClass object, itself, before you try to access its properties. Make sure the class object itself has been properly initialized (whether for the reasons I list above, or some other initialization problem) before you try to use its properties. You can do something like NSLog(#"CustomClass object = %#", customObject); or NSAssert(customObject, #"Object not properly initialized");.
Have you defined a #property for the CustomClass? If so, have you assigned a value?
If not, then you're sending the message variable to nil. And in your case that will result to 0.