OC 中,覆盖属性会有怎么样的化学计量属性反应

OC中属性self.a与_a访问的区别
时间: 19:49:20
&&&& 阅读:8440
&&&& 评论:
&&&& 收藏:0
标签:在OC中我们可以通过指令@property定义属性。
OC对属性封装了许多方法,同时也会自动实现一些方法,相比实例变量,感觉更加面向对象些。
一般定义属性的方法如下,在Class Test中定义属性int a。
@interface Test:NSObject
-(void) changeAValue:(int) newV
在类的实例方法中,我们可以用下面两种方式来访问a属性:
1、直接用属性名访问:
-(void) changeAValue:(int) newValue
// 默认生成的属性成员变量前面会自动加上“_”前缀
2、通过self.a的形式访问
-(void) changeAValue:(int) newValue
self.a = newV
这两种访问方式有区别吗?答案是肯定的。
通过第一种方式访问,其实是类似于C++的访问方式,是直接访问的实例变量并赋值。而第二种方式,并不像其表面那么直观,它其实是通过调用编译器自动生成的对于a变量的赋值函数来实现的。即
-(void) changeAValue:(int) newValue
self.a = newV // 此处实际是调用 [self setA:newValue];
个人感觉在类中调用自身的属性,还是用self.a的形式比较好。因为它封装了访问方法,加强了我们对变量的控制,也更面向对象些。
为了说明self.a的形式更好用一点,我们可以举个例子。在Class Test中,再添加对象属性NSString* b,并指明其为一个深拷贝属性。
&pre name=&code& class=&objc&&@interface Test:NSObject
@property(copy) NSString* b, *c;
-(void) changeAValue:(int) newV
-(void) changeBValue:(NSString*) newBValue andCValue:(NSString*) newCV@end
添加实例方法changeBValue:andCValue
&pre name=&code& class=&objc&&&pre name=&code& class=&objc&&&pre name=&code& class=&objc&&-(void) changeBValue:(NSString*) newBValue andCValue:(NSString*) newCV{ &
self.b = newBV
_c = newCV
在mian函数中写测试用例:
int main(int argc, const char * argv[]) {
@autoreleasepool {
Test* testObj = [[Test alloc] init];
NSMutableString* newBValue = [NSMutableString stringWithString:@&Tom&];
NSMutableString* newCValue = [NSMutableString
stringWithString:@&&];
[testObj setBValue:&span style=&font-family: Arial, Helvetica, sans-&&newBValue &/span&andCValue:newCValue];
NSLog(@&The value of b is %@ and c is %@&, testObj.b, testObj.c);
[name appendString:@&andLily&];
[email appendString:@&andLily&];
NSLog(@&The value of b is %@ and c is %@&, testObj.b, testObj.c);
运行,得到结果为
可以看到,b的值仍然是Tom,而c的值已经跟随这newCValue的值做了改变,末尾添加了“andLily”字符串。
我们的原意是对类属性的赋值应当是深拷贝赋值(在@property声明中添加了copy关键字),但现在b是深拷贝,而c仍然是默认的浅拷贝。究其原因,就是因为一个调用了self来访问,另一个直接对类属性进行了访问。在调用self的赋值方法访问时,编译器会自动根据copy关键字生成对应的深拷贝赋值函数,其实现类似于:
-(void) setB:NSString* newValue
if ( _b! = newValue)
_b = [newValue copy];
b已经和外部不指向同一块内存,因此b的值没有随着外部而改变。
从上面的例子可以看出,我们在类中,应该尽量使用self.a的形式来访问属性,这样对属性的访问会更加可靠简单,否则就需要我们自己实现对应属性的存取方法。
关于类的属性,还有下面几点要注意:
1、类的属性仅在本类中可以访问,子类无法通过_a的形式访问。但是可以通过继承父类的存取方法访问。
2、当声明类的属性后,编译器会自动生成对应的存取方法,但是我们仍然可以通过重写的方式,阻止编译器自动为我们生成存取方法,而是使用我们自己定义的存取方法。标签:
&&国之画&&&& &&&&chrome插件&&
版权所有 京ICP备号-2
迷上了代码!对OC中Category 的理解,以及方法覆盖的解决办法 - 简书
对OC中Category 的理解,以及方法覆盖的解决办法
在OC 中,使用category会让我们在开发中非常方便,可以为某个类增添方法,对类别自己有一点小小的体会,首先先来介绍一下类别类别是在运行时决定的,在运运行时才会分配相应的内存空间,在就决定了在编译期是不能给某个类增加属性,否则会影响内存布局,从而导致crash ,若想给某个类增加一个属性,需要在运行时添加,首先先介绍下类别的结构typedef struct category_t {
const char *classref_struct method_list_t *instanceMstruct method_list_t *classMstruct protocol_list_t *struct property_list_t *instanceP} category_t; 这个结构体理念包含这个类别的名字,实例方法,类方法,协议名,和实例属性正如我们所知的那样,当我们重写类的一个方法以后,会覆盖原来类的方法,它为什么会覆盖原来类的方法呢,我们先来看一下当调用一个方法的时候是怎么运行的BOOL classExists = NO;
if (cat-&instanceMethods ||
cat-&protocols||
cat-&instanceProperties){addUnattachedCategoryForClass(cat, cls, hi);if (isRealized(cls)) {remethodizeClass(cls);classExists = YES;}if (PrintConnecting) {_objc_inform("CLASS: found category -%s(%s) %s",getName(cls), cat-&name,classExists ? "on existing class" : "");}}if (cat-&classMethods
cat-&protocols/* ||
cat-&classProperties */){addUnattachedCategoryForClass(cat, cls-&isa, hi);//关联映射if (isRealized(cls-&isa)) {remethodizeClass(cls-&isa);//添加事件}if (PrintConnecting) {_objc_inform("CLASS: found category +%s(%s)",getName(cls), cat-&name);}}
在这里面我们可以看到,是先根据isa 指针找到该类,然后在该类的方法列表里面找到该方法的实现,当重写一个类的方法后,它会将重写的方法,放在方法列表的第一位,当第一次找到该方法的时候就不会在查找,就会执行重写的方法实现,如果我们想执行原来的方法实现就可以跳过方法列表前面的方法实现,执行最后一个该方法的实现就可以了Class currentClass = [MyClass class]; MyClass *my = [[MyClass alloc] init];if (currentClass) {unsigned int methodCMethod *methodList = class_copyMethodList(currentClass, &methodCount);IMP lastImp = NULL;SEL lastSel = NULL;for (NSInteger i = 0; i & methodC i++) {Method method = methodList[i];NSString *methodName = [NSString stringWithCString:sel_getName(method_getName(method))encoding:NSUTF8StringEncoding];if ([@"printName" isEqualToString:methodName]) {lastImp = method_getImplementation(method);lastSel = method_getName(method);}}typedef void (*fn)(id,SEL);if (lastImp != NULL) {fn f = (fn)lastIf(my,lastSel);}free(methodList);} 上面的printName为重写的方法名,获取最后一个类名和方法实现,这样就可以调用被重写的方法实现。前面提到不可以在编译期给类增加属性,那可以在运行期动态的给某个类添加属性,可以调用message API来实现+ (void)load {NSLog(@"%@",@"load in Category1");}- (void)setName:(NSString *)name{objc_setAssociatedObject(self,"name",name,OBJC_ASSOCIATION_COPY);}- (NSString*)name{NSString *nameObject = objc_getAssociatedObject(self, "name");return nameO} 我们对某个类得分类中增加一个name 属性,重写name 的set 和get方法就可以为其添加属性了,此外给大家奉上我做的一个相关的demo 地址此外在此谢谢美团技术团队的技术分享
/library/content/navigation/#section=Platforms&topic=iOS【转】iOS中属性与成员变量的区别
一、类Class中的属性property
  在ios第一版中,我们为输出口同时声明了属性和底层实例变量,那时,属性是oc语言的一个新的机制,并且要求你必须声明与之对应的实例变量,例如:
@interface MyViewController :UIViewController
UIButton *myB
@property (nonatomic, retain) UIButton *myB
  最近,苹果将默认编译器从GCC转换为LLVM(low
level virtual machine),从此不再需要为属性声明实例变量了。如果LLVM发现一个没有匹配实例变量的属性,它将自动创建一个以下划线开头的实例变量。因此,在这个版本中,我们不再为输出口声明实例变量。
  例如:MyViewController.h文件
@interface MyViewController :UIViewController
@property (nonatomic, retain) UIButton *myB
  在MyViewController.m文件中,编译器也会自动的生成一个实例变量_myButton。那么在.m文件中可以直接的使用_myButton实例变量,也可以通过属性self.myButton.都是一样的。
  注意这里的self.myButton其实是调用的myButton属性的getter/setter方法。这与C++中点的使用是有区别的,C++中的点可以直接访问成员变量(也就是实例变量)。
  例如在oc中有如下代码
  .h文件
@interface MyViewController :UIViewController
NSString *
  .m文件中,self.name
这样的表达式是错误的。xcode会提示你使用-&,改成self-&name就可以了。因为oc中点表达式是表示调用方法,而上面的代码中没有name这个方法。
  oc语法关于点表达式的说明:"点表达式(.)看起来与C语言中的结构体访问以及java语言汇总的对象访问有点类似,其实这是oc的设计人员有意为之。如果点表达式出现在等号
= 左边,该属性名称的setter方法将被调用。如果点表达式出现在右边,该属性名称的getter方法将被调用。"
  所以在oc中点表达式其实就是调用对象的setter和getter方法的一种快捷方式,&例如:dealie.blah
= greeble 完全等价于 [dealie.blah setBlah:greeble];
&  以前的用法,声明属性跟与之对应的实例变量:
@interface MyViewController :UIViewControlle
UIButton *myB
@property (nonatomic, retain) UIButton *myB
  这种方法基本上使用最多,现在大部分也是在使用,因为很多开源的代码都是这种方式。但是ios5更新之后,苹果是建议以以下的方式来使用:
@interface MyViewController :UIViewController
@property (nonatomic, retain) UIButton *myB
  因为编译器会自动为你生成以下划线开头的实例变量_myButton,不需要自己手动再去写实例变量。而且也不需要在.m文件中写@synthesize&myButton;也会自动为你生成setter,getter方法。@synthesize的作用就是让编译器为你自动生成setter与getter方法。
  @synthesize&还有一个作用,可以指定与属性对应的实例变量,例如@synthesize
myButton = xxx;那么self.myButton其实是操作的实例变量xxx,而不是_myButton了。
  在实际的项目中,我们一般这么写.m文件
@synthesize myB
  这样写了之后,那么编译器会自动生成myButton的实例变量,以及相应的getter和setter方法。注意:_myButton这个实例变量是不存在的,因为自动生成的实例变量为myButton而不是_myButton,所以现在@synthesize的作用就相当于指定实例变量;
  如果.m文件中写了@synthesize&myB那么生成的实例变量就是myButton;如果没写@synthesize&myB那么生成的实例变量就是_myButton。所以跟以前的用法还是有点细微的区别。
&二、类别中的属性property
  类与类别中添加的属性要区分开来,因为类别中只能添加方法,不能添加实例变量。经常会在ios的代码中看到在类别中添加属性,这种情况下,是不会自动生成实例变量的。比如在:UINavigationController.h文件中会对UIViewController类进行扩展
@interface UIViewController (UINavigationControllerItem)
@property(nonatomic,readonly,retain) UINavigationItem *navigationI
@property(nonatomic) BOOL hidesBottomBarWhenPushed;
@property(nonatomic,readonly,retain) UINavigationController *navigationC
  这里添加的属性,不会自动生成实例变量,这里添加的属性其实是添加的getter与setter方法。
  注意一点,匿名类别(匿名扩展)是可以添加实例变量的,非匿名类别是不能添加实例变量的,只能添加方法,或者属性(其实也是方法)。
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。在 SegmentFault,解决技术问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。
一线的工程师、著名开源项目的作者们,都在这里:
获取验证码
已有账号?
标签:至少1个,最多5个
在编写一个自定义相册的功能的时候,由于需要继承 UINavigationController写一个ImagePickerViewController,同时ImagePickerViewController又需要和其他的类进行沟通,所以很自然的,ImagePickerViewController类就需要有一个delegate属性,而且需要要求这个属性是一个实现了自定义的ImagePickerViewControllerDelegate协议的属性,那么这个时候问题就来了:父类是已经有一个这样的属性的。直接这么写编译器就会给出一个 warning:
Auto property synthesis will not synthesize property 'delegate'; it will be implemented by its superclass, use
to acknowledge intention
诚然我们可以通过声明一个类似delegateObj的属性来避开这个问题,不过为何编译器会给出这个 warning 却值得研究。
要想研究这个问题首先得从什么是属性开始讲起,在 oc 中属性就是给一个类的成员变量提供封装:
Objective-C properties offer a way to define the information that a class is intended to encapsulate。
通过声明属性,我们可以很简单的为一个成员变量定义其是否是只读的还是读写的,是否是原子操作的等等特性,也就是说如果说封装是为成员变量套了一层壳的话,那么 @property关键字做的事情就是预定义这层壳是个什么样子的壳,然后通过 @sythesize关键字生成真正的壳并把这个壳套在实际的成员变量上(如果没有定义这个成员变量该关键字也可以自动生成对应的成员变量)。当然这层壳包括了自动生成的 get set 方法。
在最开始的时候,我们在代码中写了@property对应的就要写一个@sythesize,在苹果使用了 LLVM 作为编译器以后,如果我们没有写 @sythesize,编译器就会为我们自动的生成一个 @sythesize property = _property。这个特性叫做Auto property synthesize。
说了这么多,现在我们来回头看看问题的关键,当我们想覆盖父类的属性并做一些修改的时候,Auto property synthesize这个特性就有点不知道该干嘛了,这个时候他选择不跑出来为我们干活,所以编译器就不会自动生成@sythesize property = _property,但是子类总得有个壳啊,人家都有@property了,怎么办?直接拿过来父类的壳复制一份不管三七二十一套在子类的成员变量身上。注意,有些情况下这会产生运行时的 crash,比如:
一个父类 A
@interface A : NSObject
@property(strong,nonatomic,readonly)NSString *
@interface Aa : A
@property(strong,nonatomic,readwrite)NSString *
这种情况下编译器会给出 warning:
Auto property synthesis will not synthesize property 'name' because it is 'readwrite' but it will be synthesized 'readonly' via another property
注意,虽然只给出了 warning,但是这个时候显然 Aa 中是不会自动生成 set 方法的,如果在代码中调用了 Aa 的实例对象的 set 方法,运行时就会 crash,crash 原因是:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Aa setName:]: unrecognized selector sent to instance
所以遇到这个问题怎么解决?在子类中显式的声明一个@synthesize name = _就好,这样子类就会如愿的产生他的壳,编译器也不纠结了,就去掉了 warning,从此,天下太平~
0 收藏&&|&&0
你可能感兴趣的文章
13 收藏,18k
11 收藏,1.5k
5 收藏,1.3k
本作品采用 署名-非商业性使用-禁止演绎 4.0 国际许可协议 进行许可
今天遇到这个场景,用 @synthesize name = _ 不成功。使用 @ 解决。需要注意的是 @dynamic 关键字不会自动生成 setter 和 getter 方法,但由于子类已经继承了父类的 setter 和 getter ,可以不用写。
今天遇到这个场景,用 `@synthesize name = _` 不成功。使用 `@` 解决。
需要注意的是 `@dynamic` 关键字不会自动生成 **setter** 和 **getter** 方法,但由于子类已经继承了父类的 **setter** 和 **getter** ,可以不用写。
怎么个不成功法?用@dynamic得注意父类和子类的读写设定是一样的~
怎么个不成功法?用`@dynamic`得注意父类和子类的读写设定是一样的~
场景是子类继承了父类的协议,父类和子类分别有 id&FatherDelegate& delegate 与 id&SonDelegate& delegate 两个属性,在子类中使用 @synthersize delegate = _ 时提示子类 delegate 尝试使用父类声明的实例变量 _delegate ,且二者类型不匹配。
场景是子类继承了父类的协议,父类和子类分别有 id&FatherDelegate& delegate 与 id&SonDelegate& delegate 两个属性,在子类中使用 @synthersize delegate = _ 时提示子类 delegate 尝试使用父类声明的实例变量 _delegate ,且二者类型不匹配。
这个warning是说子类的属性类型和从父类继承的不符合,但是实际情况应该还是覆盖了父类的继承的属性,如果想让这个 warning 消失掉,只要把子类的协议声明成:@protocol Son &NSObject,Father&就行,用@dynamic后 get 和 set 方法应该获取到的是父类类型的 delegate
这个`warning`是说子类的属性类型和从父类继承的不符合,但是实际情况应该还是覆盖了父类的继承的属性,如果想让这个 warning 消失掉,只要把子类的协议声明成:`@protocol Son &NSObject,Father&`就行,用`@dynamic`后 get 和 set 方法应该获取到的是父类类型的 delegate
虽然用 @synthersize 还是不行 不过谢谢你的解答
虽然用 `@synthersize` 还是不行 不过谢谢你的解答
分享到微博?
我要该,理由是:}

我要回帖

更多关于 化学的自然与社会属性 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信