美文网首页
【GeekBand】objective-c basic1

【GeekBand】objective-c basic1

作者: JeremyWang | 来源:发表于2016-05-12 15:20 被阅读0次
  • 类与对象
  • 数据成员
  • 函数成员

TODO:

  • 初始化器和析构器
  • 继承
  • 多态

类与对象

Objective-C(以下简称OC) 是一种面向对象语言,因此除了基本数据类型,它具有类类型。OC 中类的声明形式类似:

 @interface MyClass: NSObject
 {
  NSString* private;  //实例变量
  @public NSString* public; //实例变量
 }
 @property int num;  //属性
 
 -(void)ObjectMethod: (int)num; //对象方法,又叫实例方法
 +(void)ClassMethod; //类方法
 
 -(NSString*)private ;
 -(void)setPrivate: (NSString*)str;
 
 @end

OC 用 @interface 声明类,相当于C++语法中的class关键字。@end表示声明的结束。OC中的大部分中大部分类都会直接或者间接继承自NSObject,这是因为NSObject中定义了一些OC对象通用的方法,比如定义一个类时[[MyClass alloc] init],其中allocinit方法就是在NSObject中定义的,否则我们就要在类定义中自己实现这两个方法。

OC中类的声明放在.h文件,类是现实存在.m文件。上面声明的类其实现类似:

 @implement MyClass
 
 -(void)ObjectMethod: (int)num
 {
  self.num = num;
 }
 
 +(void)ClassMethod 
 {
  NSLog(@"This ClassMethod");
 }
 
 -(NSString*)private {
  return private;
 }
 
 -(void)setPrivate: (NSString*)str {
  private = str
 }

定义一个类对象的语法如下:

 MyClass* myClass = [[MyClass alloc] init]

大概是因为OC中的类对象都是分配在堆上的,所以,类对象都声明为指针的形式。

数据成员:属性和实例变量

上述类声明中的有一个数据成员,就是

@property in num;

属性的存取方式

myClass.num = 5;
int someNum = myClass.num;

对于任何属性,编译器都会自动生成一个与之关联的实例变量。比如与num关联的实例变量是_num。同时还生成一个getter访问器方法和一个setter访问器方法。

-(int)num {
 return _num;
}

-(void)setNum: (int)num {
 _num = num;
}

可以发现这里的_num和它的两个访问器和我们在MyClass实现中定义的NSString* private;形式是类似的。
privatepublic一样是实例变量,不同的是,一般的实例变量(如:private)只能在类的内部访问,都是私有的。为了能在类的外部访问(如myClass->public = @"hello";),需要在实例变量声明语句加上@public前缀(如:public)。
虽然private不能在外部通过->来访问,但因为我们为private编写了getter访问器和setter访问器,在OC中,我们就可以使用myClass.private = @"world"这样的语法来访问private,其实编译器会自动将该语句转化成[myClass setPrivate:@"world"],也就是实际是调用setter方法来访问private实例变量的。
可想而知,如果没有属性,那么对于每个我们希望通过myClass.XXX形式来访问的实例变量,我们都需要为其编写两个访问器方法,这实在是太过繁琐。有了属性这个语法糖,就可以让编译器自动为我们完成这些工作了。
同样,有了属性,我们也不需要再使用@public关键字,通过->指针访问符来访问实例变量了。

需要注意的时,对于在.h.m文件中分别编写类声明和类实现代码情况,即我们通常所遵循的方式。外部使用时通过#import "xxx.h"只能知道xxx.h文件中的定义,如果我们将某个实例变量定义在xxx.m的实现代码中,那么就是为该实例变量加上@public前缀,外部对象也不能访问该实例变量,因为它根本不知道该实例变量的存在。这点对于方法也是成立的,尽管方法都是public的,但如果方法只在.m文件中定义,没有在.h文件中声明,那么对于外部对象该方法就相当于是私有的。相当于私有并不等于私有,这点在编译器报错时可以体现。只定义在.m文件中情况,访问时编译器会提示没有定义该实例变量或者方法,而如果是声明在.h文件中非@public实例变量,访问时编译器会提示该实例变量是受保护的。

函数成员:方法

OC中的方法都是public的,没有 private 和 protected 方法。
OC中类的方法分为实例方法类方法,声明形式如下

-(void)ObjectMethod: (int)num; //对象方法,又叫实例方法
+(void)ClassMethod; //类方法

在语法层面,实例方法就是通过实例对象来调用的方法,如[myClass ObjectMethod:10],定义时在方法名前加-前缀;类方法就是通过类名来调用的方法,如[MyClass ClassMethod],定义时在方法名前加+前缀。
[[MyClass alloc] init],其中alloc就是类方法,init就是实例方法。

类方法中是不能访问本类的实例成员的。在逻辑上类方法可以在类对象不存在时调用,此时实例变量都还不存在,那么通过类方法访问实例成员必然出错。即使类对象存在,假设有多个类对象,那么类方法是访问那个类对象的实例成员也是无法确定。在实现上,编译器会为实例方法自动添加指向当前对象的self指针参数,通过self就能确定所访问的对象。而类方法是没有self参数的,所以类方法无法确定是哪个类对象。

OC中方法的外部参数名不同,就是不同的方法。因此可以写方法名相同,参数类型和数量相同,以及返回值相同的,只有外部参数名不同的多个方法。

-(void)sum: (int)arg1 arg2: (int)arg2;
-(void)sum:(int)arg1 secondArg: (int)arg2;

这样的两个方法是可以同时存在的。

初始化器和析构器

初始化器

    MyClass* myClass = [[MyClass alloc] init]

OC中创建一个对象需要配合使用allocinit两个方法。正如方法名的字面意思,alloc方法用于分配对象空间,init方法用于对对象的实例变量进行初始化操作。
alloc方法在NSObject中已经定义,这也是我们的类要继承于NSObject的原因之一。alloc方法会将分配的内存空间用0来填充,这样所有的实例变量的值就会是0或者nil。
init的方法中,会先调用父类的init方法,再初始化自己的实例变量。
init是对象初始化器,在调用init之前还会调用一个类初始化器initialize

@implementation MyClass 
...
-(id)init {
    self = [super init];
    NSLog(@"this init");
    return self;
}

+(void)initialize {
    if self == [MyClass class] {
        NSLog(@"this is initialize");
    }
}
...
@end

在类定义中实现这两个初始化器,然后调用MyClass* myClass = [[MyClass alloc] init]
会输出如下结果:

结果

类型初始化器initialize只能有一个,而对象初始化器init可以有多个。

- (id)init;
- (id)initWithName: (NSString*)name;
- (id)initWithLocation: (NSPoint*)location;

在初始化器中,要使用实例变量,不要使用属性。

析构器 dealloc

在析构器中,主要做三件事

  1. ARC对对象属性的引用计数器减1,这个造作是自动完成。
  2. 手动释放我们自己分配的动态内存
  3. 关闭非内存资源,比如文件句柄,socket连接等

相关文章

网友评论

      本文标题:【GeekBand】objective-c basic1

      本文链接:https://www.haomeiwen.com/subject/djlprttx.html