首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >基础篇-ObjectC继承、类别、属性

基础篇-ObjectC继承、类别、属性

作者头像
進无尽
发布2018-09-12 18:40:39
1.7K0
发布2018-09-12 18:40:39
举报
文章被收录于专栏:進无尽的文章進无尽的文章
前言

    在实际的开发过程中,继承和类别都会得到很多用处。对于界面相似度很高的情况下,使用继承可以节省很多代码和设置,只需要在子类中重写父类中的方法,或者增加新的子类方法即可,代码非常的简洁维护起来也很方便。下面小节下相关的知识,供需要的朋友查看。    在Objective-C中,给一个类扩展一个其它方法,有两种实现方式:类别和继承。


 继承

 这个是面向对象语言都有的一个特性,子类会继承父类的方法属性以及成员变量。  这里说的方法需要在 父类中的 .h中声明,子类才可以使用super 调用父类的方法,可以继承过来父类的一切属性,可以使用父类的成员变量。

.h 文件相当于一个对外公开的 head ,是因为 oc 中无法导入 .m 文件,只能导入.h 文件,所有子类中需要用到父类中导入的头文件的话,这个头文件需要在 父类的.h  中导入,子类无法调用 父类 .m 中导入的头文件 和声明的 成员变量。所以把 .m 文件中的东西相当于是 私有的,不会被非本类的对象所调用。

 在继承中需要注意的是:重写的这个方法在父类中执行时会替换掉原来的方法的(就算子类中没有调用这个新重写的方法这个新方法也已经被执行了),一般自己不调用这个重写的方法,子类一般只调用新加的方法。

  在 .h 中声明成员变量,又不想被子类调用,可以对这个成员变量进行限定如:

@private NSMutableArray*modelArray;

@private 私有成员,只有当前类可以访问; @protected 受保护成员,只有当前类或子类可以访问(如果没有添加任何修饰则默认为@protected); @public 公共成员,所有类均可访问;

类别category

这是Objective-C语言的一个特性,可以在不改变类名和原来类的实现的前提下,实现对类的方法扩展。

以下两种方式最好使用类别。

1)针对系统提供的一些类,例如:NSString,NSArray,NSNumber等类,进行方法扩充的时候。

2)类别支持开发人员针对自己构建的类,把相关的方法分组到多个单独的文件中,对于大型而复杂的类,这有助于提高可维护性,并简化单个源文件的管理。

对于以下情况,无法使用类别,必须使用继承。

1)新扩展的方法与原方法同名,但是还需要使用父类的实现。因为使用类别,会覆盖原类的实现(继承也会覆盖,就是所谓的重写,但是可以在重写的时候调用  父类的同名方法,而类别不能),无法访问到原来的方法。

2)扩展类的属性,这个类别无法做到。

OC中的子类可以拥有和父类相同名称的方法,在子类调用时,优先去自己的内部寻找,如果没有则一层一层的往上找;

(4)OC语言是单继承语言。在OC语言中,基本上所有类的根类都是NSObject类。

提示:重写即子类重新实现了父类中的某个方法,覆盖了父类以前的实现。

提示:每个类中都有一个super class指针,该指针指向自己的父类。对象中有一个isa指针,该指针指向调用该对象的类。

继承的好处:

(1)抽取出了重复的代码

(2)建立了类和类之间的联系

继承的缺点:耦合性太强

属性

在OC中定义变量,可以自己来定义变量的setter方法来设置变量值,用getter方法来获取变量值,但是当变量数量增多时,还采用手动添加setter/getter方法来操作变量,就会使得程序代码量大大增加,于是就出现了 @property 来快速声明设置获取变量的值的方法,这也许就是  @property @synthesize/@dynamic 设计的本意。 @property是给编辑器看的。就算你不声明@property,在obj的@implenmention下写好valueA和setValueA,还是可以obj.valueA赋值或取值,但是没有自动联想。 只声明@property而不去实现,在Xcode4.4以后会自动帮你生成get和set方法 本质上来讲,属性也会帮你定义一个成员变量,并根据属性的声明自动生成getter/setter 方法,其中setter 方法根据属性(property)的属性(attribute)来提供不同的内存管理策略。

@property是一个属性访问声明以及声明getter,setter方法

扩号内支持以下几个属性:(getter=getterName,setter=setterName,设置setter与getter的方法名,retain,copy,assign.......)

在声明property属性后,有2种实现选择

@synthesize  作用是实现属性的,如getter,setter方法. (通过类别和runtime 的对相关联技术生成新的属性时,无法使用这个这个设置,只能使用@dynamic)

编译器期间,让编译器自动生成getter/setter方法。

当有自定义的存或取方法时,自定义会屏蔽自动生成该方法

@dynamic

告诉编译器,不自动生成getter/setter方法,避免编译期间产生警告

然后由自己实现存取方法

如果@synthesize和@dynamic都没写,那么默认的就是@syntheszie var = _var;

我们来看一下属性的本质和进化过程:

原始形态

    定义一个实例变量:int age;

    先在.h文件中声明setter和getter器     -(void)setAge:(int)newAge;      -(int)age;

然后在.m文件中具体实现

-(void)setAge:(int)newAge {      age=newAge; } -(int)age {  return age; }

这样的话就可以跟属性一样使用了。

//比如上面的声明是一个Person类 Person*person=[[Person alloc]init]; [person setAge:13]; int age=[person age];

//点调用

person.age=13;  //.调用出现在=号左边,相当于setter intage=person.age   //.调用出现在=号的右边,相当于getter NSLog(@"%i",person.age);//这也是getter

setter和getter的改进写法:

每次要为一个属性写上getter和setter,不得不手十分麻烦,所以有了更简单的写法,

在.h文件里,直接这样写,表示声明了一个实例属性和它的getter和setter器

@property int age;

然后在.m文件中这样写,

@synthesize age;

表示实现setteer和getter,这样,就可以和以前一样调用getter和setter了。

setter和getter的改进优化:

可以看到,getter器的方法名直接就是变量名,方法名和变量名一样,容易让人迷糊,所以,可以这样优化。

在.h文件中依然这样声明

@property int age;

在.m文件中,这样去写,

@synthesizeage=_age; //加上一个_

//这么,我们就可以去使用_age   和使用age一样

-(void)show { NSLog(@"%i",_age); }

可以看出来,在Objective-C中setter器没什么区别,不过getter器的方法名缺少了get,因为get...在Objective-C有别的用处,所以getter器直接写的就是变量名。

     1. 如果只声明一个属性a,不使用@synthesize实现:编译器会使用_a作为属性的成员变量(如果没有定义成员变量_a则会自动生成一个私有的成员变量_a;如果已经定义了成员变量_a则使用自定义的成员变量_a。注意:如果此时定义的成员变量不是_a而是a则此时会自动生成一个成员变量_a,它跟自定义成员变量a没有任何关系);

      2.如果声明了一个属性a,使用@synthesize a进行实现,但是实现过程中没有指定使用的成员变量(例如上面birthday):则此时编译器会使用a作为属性的成员变量(如果定义了成员变量a,则使用自定义成员变量;如果此时没有定义则会自动生成一个私有的成员变量a,注意如果此时定义的是_a则它跟生成的a成员变量没有任何关系);

      3.如果声明了一个属性a,使用@synthesize a=_a进行实现,这个过程已经指定了使用的成员变量:此时会使用指定的成员变量作为属性变量;(那还不如不写这个 @synthesize ..)

有了上面的总结,相信理解上面的代码并不难,通常在实际开发过程中我们要么直接在@property中声明不使用@synthesize;要么使用过程中指定具体的成员变量。

此外再次强调一下,通过上面的方式定义变量的本质还是生成对应的gettter、setter方法(只是这个步骤编译器帮你完成了),如果通过@property定义了属性,同时在.m中又自定义实现了对应方法,则会使用自定义方法。

定义setter的语义

nonatomic 禁止多线程,变量保护,提高性能。 atomic    是Objc使用的一种线程保护技术,基本上来讲,是防止在写未完成的时候被另外一个线程读取,造成数据错误。而这种 机制是耗费系统资源的 assign   此标记说明设置器直接进行赋值 ,赋值特性,不涉及引用计数,弱引用对基础数据类型 (NSInteger,CGFloat)和C数据类型(int, float,double, char)等等。 如果你要一个属性使用assign,且这个类符合NSCopying协议. retain    对其他NSObject和其子类对参数进行release旧值,再retain新值,新对象的引用计数+1; 指定retain会在赋值时唤醒传入值的retain消息。此属性只能用于Objective-C对象类型,而不能用于Core Foundation对象。(原因很明显,retain会增加对象的引用计数,而基本数据类型或者Core Foundation对象都没有引用计数——译者注)。 注意: 把对象添加到数组中时,引用计数将增加对象的引用次数+1。 copy   对NSString 它指出,在赋值时使用传入值的一份拷贝。拷贝工作由copy方法执行,此属性只对那些实行NSCopying协议的对象类型有效,表示两个对象内容相同,新的对象retain为1 ,与旧有对象的引用计数无关。 weak    weak比assign多了一个功能,当对象消失后自动把指针变成nil,好处不言而喻。弱引用除了不决定对象的存亡外,其他与强引用相同。即使一个对象被持有无数个若引用,只要没有强引用指向他,那麽其还是会被清除。 retain  是指针拷贝,copy 是内容拷贝。 iOS 5 中对属性的设置新增了strong 和weak关键字来修饰属性(iOS 5 之前不支持ARC) strong   用来修饰强引用的属性,一块内存(一个对象)当没有 strong 类型的指针指向它时,它就会被释放;ARC中使用,与MRC中retain同义,使用之后,计数器+1。 官方文档中有这样的示例代码:// The following declaration is a synonym for: @property(retain) MyClass *myObject;@property(strong) MyClass *myObject;表示了strong和retain是同义词。 weak    用来修饰弱引用的属性,当一块内存(一个对象)被释放时,指向它的 weak 类型指针就会被释放并赋值为 nil。

所以,如果一般情况下,我们都不希望字串的值跟着str变化,所以我们一般用 copy 来设置string的属性。如果希望字串的值跟着赋值的字串的值变化,可以使用 strong,retain。当然这也只是针对 NSMutableString,因为如果是 NSString 那么 copy 与 retain 的效果是一样的。

这里需要提一下,如果一个对象作为属性时,定义setter的语义使用了copy字段,那么需要遵循 <NSCopying>协议,并且需要重写 copyWithZone 方法。否则会cash。 NSZone 是苹果对内存分配和释放的优化方式。NSZone不是一个对象;它是一个难懂的C结构,它被用于纪录关于内存处理(管理)一系列对象的信息。 - (id)copyWithZone:(NSZone*)zone {     id   copy = [[[self  class]alloc]init];    if(copy){     // self.imageName 是 当前的属性      [copy   setImageName:[self.imageName copyWithZone:zone]];    }        return   copy; }

一些需要注意的知识

1.实例方法/动态方法 2.静态方法/类方法 静态方法在堆上分配内存(释放工作由程序员控制),实例方法在栈上(是由编译器自动管理) 静态方法常驻内存,实例方法不是,所以静态方法效率高但占内存


本文参考文章:

OC基础相关

属性相关

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016.04.28 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  •  继承
  • 类别category
  • 属性
  • 一些需要注意的知识
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档