irpas技术客

OC隐藏和封装_Billy Miracle

未知 5772

封装

封装是面向对象的三大特征之一(另外两大特征是继承和多态),他指将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,而是通过该类所提供的方法来实现对内部信息的操作和访问。 对一个类或对象实现良好的封装,可以实现以下目的:

隐藏类的实现细节。让使用者只能通过事先预定的方法来访问数据,从而可以在该方法里加入控制逻辑,限制对成员变量的不合理访问。可进行数据检查,从而有利于保证对象信息的完整性便于修改,提高代码的可维护性。 使用访问控制符

OC提供了4个访问控制符:@private、@package、@protected 和 @public。

@private(当前类访问权限):该成员变量只能在当前类的内部访问,在类的实现部分定义的成员变量默认为@private。@package(相同映像访问权限):该成员变量可以在当前类以及当前类的同一个映像的任意地方访问。@protected(子类访问权限):该成员变量可以在当前类、当前类的子类的任意地方访问,在类的接口部分定义的成员变量默认为@protected。@public(公共访问权限):使成员变量可以在任意地方访问。

访问控制级别如下表所示:

@private@package@protected@public同一个类中√√√√同一个映像中√√子类中√√全局范围内√

示例:

// FKPerson.h // 疯狂iOS@7隐藏与封装@1 #import <Foundation/Foundation.h> @interface FKPerson : NSObject { //使用private限制成员变量 @private NSString* _name; int _age; } -(void) setName: (NSString*) name;//设置_name成员变量的值 -(NSString*) name;//设置_name成员变量的值 -(void) setAge: (int) age;//设置_age成员变量的值 -(int) age;//获取_age成员变量的值 @end

_name 和 _age 两个成员变量位于 @private 之后,只能在当前类中访问。

// FKPerson.m // 疯狂iOS@7隐藏与封装@1 #import "FKPerson.h" @implementation FKPerson -(void) setName:(NSString *)name { if([name length] >6 || [name length] < 2) { NSLog(@"您设置的人名不符合要求"); return; } else { _name = name; } } - (NSString*) name { return _name; } -(void) setAge:(int)age { if(_age != age) { if (age > 100 || age < 0) { NSLog(@"您设置的年龄不合法"); return; } else { _age = age; } } } - (int) age { return _age; } @end // main.m // 疯狂iOS@7隐藏与封装@1 #import "FKPerson.h" int main(int argc, const char * argv[]) { @autoreleasepool { //因为_age成员变量已隐藏,所以下面的语句编译错误 //如果改为@package就可以操作了 //p->_age = 1000; FKPerson* p = [[FKPerson alloc] init]; [p setAge: 1000]; NSLog(@"未能设置_age成员变量时:%d", [p age]); [p setAge: 30]; NSLog(@"成功设置_age成员变量后:%d", [p age]); [p setName:@"李刚"]; NSLog(@"成功设置_name成员变量后:%@", [p name]); } return 0; }

模块设计讲求高内聚(尽可能把模块的内部数据、功能实现细节隐藏在模块内部独立完成,不允许外部直接干预),低耦合(仅暴露少量的方法给外部使用)。 关于访问控制符的使用,存在如下几条基本原则:

类里的绝大部分成员变量都应该使用@provate限制。此外,一些工具方法也应该隐藏在该类的内部,此时应该把这些方法定义在类的实现部分。如果某个类主要作为其他类的父类,则可以考虑使用@protected。希望暴露出来给其他类自由调用的方法应该先在类接口部分定义,然后在类实现部分实现它们。 深入理解@package访问控制符

@package让那些受它控制的成员变量不仅可以在当前类中访问,也可以在同一映像的其他程序中访问。 所谓同一映像,就是编译后生成的同一个框架或同一个执行文件。当编译器最后把@private限制的成员变量所在的类、其他类和函数编译成一个框架库之后,这些类、函数都在同一个映像中,由于其他程序只是依赖这个框架库,其他程序与该框架库就不在同一个映像中。示例:

//FKApple.h #import <Foundation/Foundation.h> @interface FKApple : NSObject { @package double _weight; } @end //main.m #import "FKApple.h" int main(int argc, const char * argv[]) { @autoreleasepool { FKApple* apple = [[FKApple alloc] init]; apple->_weight = 30; NSLog(@"APPLE的质量为:%g", apple->_weight); } return 0; }

FKApple类和main()函数位于同一映像中,因此mian()函数可以自由访问FKApple类的_weight成员变量。

合成存取方法

Objective-C 2.0 开始,可自动生成设值方法(setter)和取值方法(getter)。

第一步是在类的接口部分使用@property指令定义属性第二步可选,如果程序需要改变getter、setter方法对应的成员变量的变量名,则可以在类的实现部分使用@synthesize指令。

Xcode的模版代码为:@synthesize window = _window,从中可以看出,系统合成的成员变量为property名前加下划线。 如果@synthesize指令后无指定成员变量名,则成员变量名与合成的getter方法同名。 示例:

// Fraction.h #import <Foundation/Foundation.h> @interface Fraction : NSObject @property int numerator, denominator; -(void) print; -(void) setTo: (int) n over: (int) d; -(double) convertToNum; -(void) add: (Fraction*) f; -(void) reduce; @end // Fraction.m #import "Fraction.h" @implementation Fraction @synthesize numerator; //@synthesize denominator = _denominator; //此处省略@synthesize与上面的代码效果相同 //可观察到下面的numerator与_denomiator的区别 //二者一个有下划线,一个没有 -(void) print { NSLog(@"%i/%i", numerator, _denominator); } -(double) convertToNum { if(_denominator!=0){ return (double) numerator / _denominator; } else { return NAN; } } -(void) setTo:(int)n over:(int)d { numerator = n; _denominator = d; } -(void) add:(Fraction *)f { numerator = numerator * f.denominator + _denominator * f.numerator; _denominator = _denominator * f.denominator; [self reduce]; } -(void) reduce { int u = numerator; int v = _denominator; int temp; while (v != 0) { temp = u % v; u =v; v = temp; } numerator /= u; _denominator /= u; } @end // main.m #import "Fraction.h" int main(int argc, const char * argv[]) { @autoreleasepool { id aFraction = [[Fraction alloc] init]; Fraction *bFraction = [[Fraction alloc] init]; [aFraction setTo: 1 over: 4]; //[bFraction setTo: 1 over: 2]; [bFraction setNumerator: 1]; [bFraction setDenominator: 2]; [aFraction print]; NSLog(@"+"); //[bFraction print]; //[bFraction print]; NSLog(@"%i/%i",[bFraction numerator], [bFraction denominator]); NSLog(@"="); [aFraction add: bFraction]; //[aFraction reduce]; [aFraction print]; NSLog(@"%lf",[aFraction convertToNum]); } return 0; }

以上代码实现了简单的分数相加,并使用了合成的setter与getter方法。 当使用@property定义property时,还可在@property和类型之间用括号添加一些额外的指示符:

assignatomic(nonatomic)copy:调用setter方法对成员变量赋值时,会将被赋值的对象复制一个副本,再将该副本赋给成员变量。当成员变量的类型是可变类型,或其子类是可变类型时,被赋值的对象有可能在赋值之后被修改,此时可以使用copy指示符。

示例:

@property (copy) NSString* name;

此外,getter与setter指示符用于为合成的getter、setter方法指定自定义方法名,例如:

@property (nonatomic, getter = abc, setter = def:) int price;

注意不要忘记setter后的冒号。

点语法

点语法只是一种简化写法,其本质依然是调用getter和setter方法。因此只要该对象有getter方法,程序就可以通过点语法来获取属性值,对象只要有setter方法,程序就可以通过点语法来设置对象的属性值。 示例:

bFraction.numerator = 1;


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #OC隐藏和封装 #OC隐藏和封装简介