【问题标题】:@dynamic property in Objective CObjective C 中的@dynamic 属性
【发布时间】:2019-02-21 21:13:34
【问题描述】:

我正在尝试在我的项目中实现动态属性 这是我的代码。

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

但是当我运行我的应用程序时崩溃了。

当我使用 ivar 时出现此错误。

【问题讨论】:

  • 为什么要在这里使用@dynamic@dynamic 用于在编译时不提供实现但稍后通过 Objective-C 运行时魔法添加它的属性。既然您在这里提供了一个 setter,显然情况并非如此,所以……您想要做什么
  • 这只是一个例子@CharlesSrstka
  • 但是一个什么的例子?你想做什么?
  • 我同意在此处使用@dynamic 是无用且具有误导性的。但这是一个非操作,它不会产生崩溃。由于无限递归,我看到堆栈溢出。
  • People.. 请不要投票为“不清楚你在问什么” - 问题很清楚:OP 不理解(1)属性、访问器和 iVar 之间的关系,(2 )如何声明iVars,以及(3)@dynamic的含义。他 (4) 将“动态属性”与@dynamic 属性混合在一起,虽然说起来听起来一样,但这并不是一回事。也许我可以在问题结束之前写一个答案..

标签: ios objective-c


【解决方案1】:

属性只是两个方法的集合:getter 和 setter。所以,当你写

@property (strong, nonatomic) NSString *name;

你真正想说的是

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

之后,每次编译器遇到obj.name 形式的表达式时,都会将其转换为[obj name]。每次看到obj.name = @"hello"; 之类的语句时,编译器都会将其转换为[obj setName:@"hello"]

接下来您必须确保该属性的行为正常。你有很多选择:

  • 手动编写 getter 和 setter,引用 iVar
  • 合成 getter 和 setter
  • 自动合成 getter 和 setter
  • 编写自定义 getter 和 setter
  • 使用@dynamic 来避免编译时警告,因为您打算使用运行时魔法。 (真的,这不是您想要做的,因为您需要先了解基础知识。)

手动编写 getter 和 setter,引用 iVar

@interface MyClass : UIView {
    NSString *_name;
}

@property (strong, nonatomic) NSString *name;

@end

在实现中

@implementation MyClass

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

@end

合成getter和setter

最后一段基本相当于这个

@interface MyClass : UIView {
    NSString *_name;
}

@property (strong, nonatomic) NSString *name;

@end

@implementation MyClass

@synthesize name = _name;

@end

自动合成 getter 和 setter

实际上,您只需使用“自动合成”即可。

@interface MyClass : UIView

@property (strong, nonatomic) NSString *name;

@end

@implementation MyClass

@end

这意味着,

  • 如果你只是声明一个属性
  • 不要打电话给@synthesize@dynamic
  • 不要实现任何自定义 getter 和 setter

上面的代码将创建一个名为 _name 的 iVar 和一个 getter 和 setter,看起来与第一个示例中的完全一样。

这意味着前两个和这个部分是等价的,因为它们产生相同的代码。

编写自定义 getter 和 setter

这就是术语“动态属性”的真正含义。例如,您可能希望名称始终为大写。所以你可以写一个这样的属性。

@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

(在上面的代码中,我将strong 更改为copy - 不用担心,这只是一个评论。这是一个真实的评论,因为uppercaseString 永远不会相同,它会始终是原件的副本。)

这可能是唯一真正有趣的案例!例如,这种属性是 UIKit 一直使用的,例如UILabeltext 属性就是这样的动态属性。它不仅设置了一些 iVar,而且还确保屏幕上的可见文本也发生变化。

@dynamic属性

他们真的很难做到正确,而且大多数时候他们不值得麻烦恕我直言。

注意:我简化了一些事情并省略了只有在使用 objc 运行时检查 API 时才能检测到的细节

【讨论】:

    【解决方案2】:

    这个 StackOverflow 答案:https://stackoverflow.com/a/1160545/7833793 很好地解释了 @synthesize@dynamic 之间的区别。如果您要委派实现访问器(获取、设置)的任务,通常使用@dynamic。在我看来,您似乎想在这里使用@synthesize。但是使用现代目标 c,您甚至不需要指定 iVar,系统会自动为您创建。

    即:

    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
    

    【讨论】:

      【解决方案3】:

      您的解决方案导致递归,因为您没有在 setter 中使用 ivar,所以您正在崩溃,请尝试以下操作:

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

      【讨论】:

      • @JosuéH。那是因为你没有声明 ivar。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-06-10
      • 1970-01-01
      • 2011-08-08
      • 2011-06-02
      • 2011-08-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多