Josué H.
Josué H.

Reputation: 1191

@dynamic property in Objective C

I'm trying to implement a Dynamic property in my project This is my code.

MyClass.h

@interface MyClass : UIView

@property (strong, nonatomic) NSString *name;

@end

MyClass.m

@implementation MyClass

@dynamic name;

-(void)setName:(NSString *)name{
   self.name = name;
}
@end

But when I run my app has crashed.

enter image description here

When I use an ivar had this error. enter image description here

Upvotes: 4

Views: 6716

Answers (3)

Michael
Michael

Reputation: 6513

A property is just a bundle of two methods: a getter and a setter. So, when you write

@property (strong, nonatomic) NSString *name;

what you are really saying is

- (NSString *)name;
- (void)setName:(NSString *)name;

After that, each time the compiler encounters an expression of the form obj.name, it translates it to [obj name]. And each time you see a statement like obj.name = @"hello";, the compiler translates it to [obj setName:@"hello"].

The next thing is you have to make sure the property behaves properly. You have many options:

  • Write getters and setters manually, referring to an iVar
  • Synthesize getter and setter
  • Autosynthesize getter and setter
  • Write custom getters and setters
  • Use @dynamic to avoid compile time warnings, because you intend to do runtime magic. (Really, that's not what you want to do, because you need to understand the basics first.)

Write getters and setters manually, referring to an iVar

@interface MyClass : UIView {
    NSString *_name;
}

@property (strong, nonatomic) NSString *name;

@end

and in the implementation

@implementation MyClass

- (NSString *)name {
    return _name;
}
- (void)setName:(NSString *)name {
    _name = name;
}

@end

Synthesize getter and setter

The last section is basically equivalent to this

@interface MyClass : UIView {
    NSString *_name;
}

@property (strong, nonatomic) NSString *name;

@end

@implementation MyClass

@synthesize name = _name;

@end

Autosynthesize getter and setter

In practice, you would just use "autosynthetisation".

@interface MyClass : UIView

@property (strong, nonatomic) NSString *name;

@end

@implementation MyClass

@end

This means,

  • if you just declare a property
  • don't call @synthesize or @dynamic
  • don't implement any custom getter and setter

the code above will just create an iVar named _name and a getter and setter that looks exactly like the one in the first example.

This means that the the first two and this sections are equivalent, because they produce the same code.

Write custom getters and setters

This is what the term "dynamic property" really means. For example, you may want the name to be always uppercase. So you may write a property like this.

@interface MyClass : UIView {
    NSString *_name;
}

@property (copy, nonatomic) NSString *name;

@end

@implementation MyClass

- (NSString *)name {
    return _name;
}

- (void)setName:(NSString *)name {
    _name = [name uppercaseString];
}

@end

(in the code above, I changed strong to copy - don't worry, this is just a comment anyways. And it's a true one, because the uppercaseString will never be the same, it will always be a copy of the original.)

This is maybe the only really interesting case! For example, this kind of property is what UIKit uses all the time, e.g. the text property of UILabel is a dynamic property like that. It doesn't just set some iVar, but it also makes sure that the visible text on the screen changes too.

@dynamic properties

they are really tricky to get right, and most of the time they are not worth the hassle IMHO.

Note: I simplified some things and left out details which are only detectable when using objc runtime inspection APIs

Upvotes: 12

R4N
R4N

Reputation: 2595

This StackOverflow answer: https://stackoverflow.com/a/1160545/7833793 does a good job of explaining what the differences between @synthesize and @dynamic are. Typically you use @dynamic if you're delegating the task of implementing the accessors (get, set). It seems to me like you would want to use @synthesize here. But with modern objective c, you shouldn't even need to specify and the iVar will be created for you automatically.

i.e.:

MyClass.h

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface MyClass : NSObject
@property (strong, nonatomic) NSString *name;
@end

NS_ASSUME_NONNULL_END

MyClass.m

#import "MyClass.h"

@implementation MyClass

- (void)setName:(NSString *)name {
    _name = name;
}

@end

Upvotes: 4

Evgeny Karkan
Evgeny Karkan

Reputation: 9672

Your solution leads to recursion, you are getting crash since you are not using ivar in setter, try this instead:

-(void)setName:(NSString *)name{
   _name = name;
}

Upvotes: 1

Related Questions