0

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!

Antony Raphel
  • 1,700
  • 2
  • 20
  • 44
iamhx
  • 292
  • 3
  • 21
  • 2
    check this ans: http://stackoverflow.com/a/7855536/4831524 – Antony Raphel Feb 20 '17 at 11:07
  • 1
    Check this links, http://stackoverflow.com/questions/2255861/property-and-retain-assign-copy-nonatomic-in-objective-c http://stackoverflow.com/a/15541801/4294543 – Mukesh Feb 20 '17 at 11:10
  • @iamhx have you given identifier in storyboard?? – Tushar Sharma Feb 20 '17 at 11:18
  • @AntonyRaphel ah, so object types use retain... Just a question, I'm thinking of learning Swift soon, would it be a waste of time to learn all these now? I had to stick with objective-c because my course syllabus in my college has not updated to Swift yet. – iamhx Feb 20 '17 at 11:29
  • @iamhx Swift is probably your best bet for general applications now. However, there are still going to be times when it's useful to have very fine-grained control over things, at which point a working knowledge of C and Objective-C will stand you in good stead. However, learn Swift as soon as you can and champion efforts for migrating objective-c to Swift. – Antony Raphel Feb 20 '17 at 11:37
  • @AntonyRaphel Cool! Thanks for the great advice! I guess it was a good thing I learnt objective-c in college :p – iamhx Feb 20 '17 at 11:46
  • `retain` is all but deprecated. Use `strong`. – jscs Feb 20 '17 at 17:49
  • @JoshCaswell Really? are there any references to the deprecation of retain? – iamhx Feb 20 '17 at 17:51
  • It's not actually deprecated, but its only correct if you're not using ARC. – jscs Feb 20 '17 at 17:51
  • @JoshCaswell I see... Thanks for the heads up! I'll update my code and see whether it still works – iamhx Feb 20 '17 at 17:52
  • @JoshCaswell, I had realised that my `NSPersistentContainer` (for CoreData) in my AppDelegate is using `@property (readonly, strong) NSPersistentContainer *persistentContainer;` From what I know properties are atomic by default. Is there a need to change this to nonatomic? – iamhx Feb 20 '17 at 17:59
  • The decision between nonatomic and atomic is really too big for a comment, but with a readonly property it's kind of moot, since there's no setter. – jscs Feb 20 '17 at 20:30

3 Answers3

1

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
Community
  • 1
  • 1
Mukesh
  • 2,636
  • 18
  • 32
1

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.

Community
  • 1
  • 1
sschunara
  • 2,245
  • 20
  • 29
0

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.

Matic Oblak
  • 14,391
  • 1
  • 24
  • 37
  • Interesting... I'd like to ask, in the `@interface {}` of a .h file you can declare stuff in it (e.g `NSString *myString;`) and use it in your .m file as `self.myString;`. My question is that in the .m file there is also an `@interface {}`. Are both of these interfaces the same thing? – iamhx Feb 20 '17 at 12:01
  • 1
    They are the same but the one in the source file (.m) is usually treated as a private (or file-private). In most cases we try to declare everything there but the values that need to be exposed to other classes, files. And those exposed should always be properties so you can control the logic without the need of changing the logic outside of that class (like overriding a setter). So in short, put all of these in source file unless you are 100% sure what you are doing like optimizing performance. – Matic Oblak Feb 20 '17 at 12:17
  • Also note that you can have the same property in both interface and source file if the interface has a read-only flag. This means you will expose the property as read-only but be able to assign to it internally within the source file. – Matic Oblak Feb 20 '17 at 12:19