@dynamic与@synthesize

@dynamic与@synthesize

@dynamic介绍:
        Apple的解释:
  @dynamic
  You use the @dynamic keyword to tell the compiler(编译器) that you will fulfill the API contract(协议合同) implied(隐藏的暗示的) by a property either by providing method implementations directly or at runtime using other mechanisms(机制机理) such as dynamic(动态的活跃的) loading of code or dynamic method resolution. It suppresses(取消抑制禁止) the warnings that the compiler would otherwise(否则) generate if it can"t find suitable implementations. You should only use it if you know that the methods will be available at runtime.
  The example shown in Listing 5-3 illustrates([ˈɪləˌstreɪt]举例说明) using @dynamic with a subclass of NSManagedObject.
  Listing 5-3 Using @dynamic with NSManagedObject
  @interface MyClass : NSManagedObject
  {
  }
  @property(nonatomic, retain) NSString *value;

  @end

  @implementation MyClass
  @dynamic value;
  @end

  NSManagedObject is provided by the Core Data framework. A managed object class has a corresponding([ˌkɔrəˈspɑndɪŋ]对应相应) schema(['ski:mə]框架模式) that defines attributes and relationships for the class; at runtime, the Core Data framework generates accessor methods for these as necessary(必须必要). You therefore typically declare properties for the attributes and relationships, but you don"t have to implement the accessor methods yourself, and shouldn"t ask the compiler to do so. If you just declared the property without providing any implementation, however, the compiler would generate a warning. Using @dynamic suppresses the warning.

  大概的翻译一下:
  @dynamic 就是要来告诉编译器,代码中用@dynamic修饰的属性,其getter和setter方法会在程序运行的时候或者用其他方式动态绑定,以便让编译器通过编译。其主要的作用就是用在NSManageObject对象的属性声明上,由于此类对象的属性一般是从Core Data的属性中生成的,Core Data框架会在程序运行的时候为此类属性生成getter和Setter方法。
        NSManagedObject属于Core Data框架。管理对象类有相应的架构定义实体的属性和关系;核心数据框架在运行时,一定会产生这些的存取方法。因此,您通常会声明的属性和关系属性,但你不需要生成自己的访问方法,也不应该要求编译器生成。然而,如果你只是声明属性但是不提供任何实现方法,编译器会生成一个警告。使用@dynamic可以抑制这种警告的产生。

@synthesize简介
      Apple的解释:
      You use the @synthesize directive(指令) to tell the compiler that it should synthesize(综合合成) the setter and/or getter methods for a property if you do not supply them within the @implementation block. The @synthesize directive also synthesizes an appropriate(适当的合适的) instance variable if it is not otherwise declared.

两者区别:
      @dynamic这个关键词,通常是用不到的。它与@synthesize的区别在于:
      使用@synthesize,编译器会确实的产生getter和setter方法,而@dynamic仅仅是告诉编译器这两个方法在运行期会有的,无需产生警告。
      假设有这么个场景:B类、C类分别继承A类,A类实现某个协议(@protocol),协议中某个属性(somePropety )我不想在A中实现,而在B类,C类中分别实现。如果A中不写任何代码,编译器就会给出警告:

“use @synthesize, @dynamic or provide a method implementation" 这时你给用@dynamic somePropety; 编译器就不会警告,同时也不会产生任何默认代码。


附1:@synthesize obj=_obj的意义详解
        我们在进行iOS开发时,经常会在类的声明部分看见类似于@synthesize window=_window;的语句.那么,这个window是什么?_window又是什么?两个东西分别怎么用,这是一个比较基本的问题,也关乎我们理解Objective-C中对类、类的属性、类的存取器、类的局部变量的统一理解。
        在32位系统中,如果类的@interface部分没有进行变量声明,但有@property声明,在类的@implementation部分有相应的@synthesize,则会得到类似下面的编译错误:
Synthesized property 'xX' must either be named the same as a compatible ivar or must explicitly name an ivar
       在64-bit时,运行时系统会自动给类添加变量,添加的变量以一个下划线"_"做前缀。
      上面声明部分的@synthesize window=_window;意思是说,window属性为_window实例变量合成访问器方法。也就是说,window属性生成存取方法是setWindow,这个setWindow方法就是_window变量的存取方法,它操作的就是_window这个变量。通过这个看似是赋值的这样一个操作,我们可以在@synthesize中定义与变量名不相同的getter和setter的命名,籍此来保护变量不会被不恰当的访问。
下面是一个常见的例子
写法一:
@interface MyClass:NSObject
{    
        MyObjecct *_myObject;  
}  
@property(nonamtic, retain) MyObjecct *myObject;  
@end  
  
@implementatin MyClass  
@synthesize myObject=_myObject;  
 
写法二:  
@interface MyClass:NSObject
{  
        
}  
@property(nonamtic, retain) MyObjecct *myObject;  
@end  
  
@implementatin MyClass  
@synthesize myObject=_myObject;  
 
         这个类中声明了一个变量_myObject,又声明了一个属性叫myObject,然后用@synthesize生成了属性myObject的存取方法,这个存取方法的名字应该是:setmyObject和getmyObject。@synthesize myObject=_myObject的含义就是属性myObject的存取方法是做用于_myObject这个变量的。这种用法在Apple的Sample Code中很常见。
        弄明白了这个语句的意思之后,我们也就清楚了myObject和_myObject的区别,那么,在使用的时候,有什么需要注意的地方,大家应该也都清楚了。是的,myObject是属性,而_myObject才是变量,我们最终操作的变量都是myObject。

那么,同样是存取操作,语句self.nameVarPtr = [[ObjectName alloc] init]; 与语句nameVarPtr = [[ObjectName alloc] init];两种赋值方式的区别何在呢?
        self.nameVarPtr=xxx 这种赋值方式等价于调用[self setnameVarPtr:xxx], 而setnameVarPtr:xxx的方法的实现又是依赖于@property的属性的,比如retain,assign等属性。
        nameVarPtr = xxx 是赋值方式,仅仅是对一个指针进行赋值。nameVarPtr仅仅是一个指针变量,记录了xxx的地址。在这个过程中不会调用setter方法,不会调用setter方法,就和@property没有关系,从而,也和retain,assign等属性没有关系。这种赋值方式就是一个简单的指针赋值。
        综上,对成员变量进行赋值,为防内存泄露需要注意的点:
       1.self调用setter方法的方式
          ObjectName*  tmp= [[ObjectName alloc] init];
          self.nameVarPtr =tmp;                 //retainCount=2
          [tmp release];                                //retainCount=1
       2.指针赋值方式,不会调用setter方法
          nameVarPtr= [[ObjectName alloc] init]; // retainCount=1
      所以,笔者建议大家在对某个变量进行赋值操作的时候,尽量要写self.myObj = xxx; 这才是最可靠的方法。

附2:@property属性举例
       读写属性
       1.readwrite:这个属性是默认的情况,会自动为你生成存取器。默认属性,将生成不带额外参数的getter和setter方法(setter方法只有一个参数)
       2.readonly:只生成getter不会有setter方法。将只生成getter方法而不生成setter方法(getter方法没有get前缀)
    
       赋值属性:
       3.assign:这个属性一般用来处理基础类型,比如int、float等等,如果你声明的属性是基础类型的话,assign是默认的,你可以不加这个属性.它不更改索引计数(Reference Counting).
       4.copy:这个会自动生成你赋值对象的克隆,相当于在内存中新生成了该对象的副本,这样一来,改变赋值对象就不会改变你声明的这个成员变量了。copy:指定应该使用对象的副本(深度复制),前一个值发送一条release消息。基本上像retain,但是没有增加引用计数,是分配一块新的内存来放置它。copy是建立一个索引计数为1的对象,然后释放旧对象,retain是创建一个指针,引用对象计数加1。

例如代码实现:
-(void)setThetest:(test *)newThetest {  
    if (thetest!= newThetest) {  
        [thetest release];  
        thetest= [newThetest copy];  
    }  
}  
       5.retain:释放旧的对象,将旧对象的值赋予输入对象,再提高输入对象的索引计数为1 ,使用retain: 对其他NSObject和其子类 ,retain,是说明该属性在赋值的时候,先release之前的值,然后再赋新值给属性,引用再加1。
例如代码实现:
-(void)setThetest:(test *)newThetest {  
    if (thetest!= newThetest) {  
        [thetestrelease];  
        thetest= [newThetest retain];  
    }  

      原子性操作
      如果使用多线程,有时会出现两个线程互相等待对方导致锁死的情况(具体可以搜下线程方面的注意事项去了解)。在没有(nonatomic)的情况下,即默认(atomic),会防止这种线程互斥出现,但是会消耗一定的资源。所以如果不是多线程的程序,打上(nonatomic)即可
       6.atomic:默认是有该属性的,就是setter/getter生成的方法是一个原子操作。这个属性是为了保证程序在多线程情况,编译器会自动生成一些互斥加锁代码,避免该变量的读写不同步问题.
例如代码实现:
[_internal lock]; // lock using an object-level lock  
//code here...
[_internal unlock];  
       7.nonatomic:非原子性访问,不保证setter/getter的原子性,多线程情况下数据可能会有问题。如果该对象无需考虑多线程的情况,请加入这个属性,这样会让编译器少生成一些互斥加锁代码,可以提高效率。

参考:
http://blog.eddie.com.tw/2010/12/08/property-and-synthesize/
http://www.cocoachina.com/bbs/read.php?tid=7322
http://www.cnblogs.com/pinping/archive/2011/08/03/2126150.html

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值