当前位置

网站首页> 程序设计 > 开源项目 > 程序开发 > 浏览文章

iOS学习笔记之 Objective-C (二)

作者:小梦 来源: 网络 时间: 2024-06-08 阅读:

上一篇文章

结尾草草地写了这么个Demo:定义一个Student类,实例化出一个xiaoming的对象,并同时使用python和java与Objective-C实现它们。这段代码只是演示了一些最基本的OC语法,但也留下了几个令初学者费解的问题:

  1. NSObject 是什么鬼?

  2. 并没有写构造方法,OC 里真的没有构造方法吗?

  3. self 是什么鬼?

  4. OC 里已经演示了如何继承和封装,但如何实现多态呢?

带着这些问题,我们继续探讨。

Objective-C中的类和NSObject

C语言中有类似对象的结构体,它可以保存一些相关的数据,在OC 里则实打实地实现了类的概念。

向类发送alloc 消息后就可以为其分配一个对象的内存空间(从语法层面上看,Javapython 是没有这一步的)。然而此时对象并没有被“构造”出来,你还需要为其发送init 消息。init 是什么呢?答:是NSObject 对象的构造方法。

初识NSObject

那么NSObject 是什么呢?答:它是OC 中大多数类的父类。尽管不像单根的java 那样是所有类的父类,但我们暂时可以不用在意这些细节。另外要说明一点的就是,OC 是单继承的,即一个子类不可能同时继承自多个父类。

诸如allocinit 这些方法都是NSObject 自带的,因此,理论上说,所有继承自NSObject 的子类都会自带这些方法。

于是我们回过头来再看xiaoming 的诞生过程,这里面就大有文章了:

   Student *xiaoming = [[Student alloc] init];   /*    1. 对Student类发送allc消息,告诉它分配内存;    2. 调用初始化方法init,完成构造。    3. 将完成构造的Student对象的内存地址赋给指针变量xiaoming   */ 

这里的init ,实际上就是发送给NSObject 发送的消息(或者说是调用了NSObject 的构造方法,发送消息这种“术语”,说起来真别扭~)。我们完全可以为自己的类指定自己的初始化方法,但在此之前,先了解一些别的东西。

有一种指针叫id 有一种空虚叫nil

id 是一个指向任何一个继承了Object(或者NSObject)类的对象,因为可以用来做泛型,有时候也叫泛型指针,但这里所谓泛型的实现方式和java 有比较大的差别。

需要注意,id 本身就表示指针,所以定义id类型的变量时请务必不要加* ,否则会报错。

nilCjava 中的NULL 相同,代表空对象,nil 并不会存在于内存中,所以当*xiaoming=nil 时,指针xiaoming 将不会指向内存中的任何一个区域。这也是释放内存的方法之一——指向原对象的指针指向nil 后,堆内存的那一坨对象就少了一处被引用,如果任何指针都没有引用那坨对象,OC会自动释放那坨对象所占的内存。OC 的内存管理我也搞不清,以后再探讨。

还有一种比较少用的首字母大写的Nil ,它和nil 的区别仅在于前者用来表示指向一个“不存在”的类。nil和Nil在使用上是没有严格限定的,它们俩可以相互替代。

再补充一个东西吧:NSNullnil 一样,也表示空,但前者拥有一个有效的内存地址,并且,这货是继承自NSObject 的。实际应用中,它常在可变数组这类东东里出现,我们暂时不去深入,知道就好。

了解selfsuperisa

selfjava 中的thispython 中的self 类似,它是一个指向类或实例本身的指针,id类型。它是类或对象的隐藏参数。

superjavapython 中的super 一样,表示指向父类,书上说,它是个编译器指示符,不明觉厉,然而这并不影响我们使用。

isa 是对象指向自己的类的指针,也是id 类型,每一个继承自NSObject 的类的实例都有它。

以上只是对NSObject 常用的一些概念的简介,并不全。

我们现在可以写一个类的构造方法了,上代码:

#import <Foundation/Foundation.h>//------  interface ------@interface Student: NSObject// 我们用 property 替代 setter/getter@property NSString *name;@property int score;// 声明构造方法1-(id)initWithName:(NSString *) newName;// 声明构造方法2-(instancetype)initWithName:(NSString *) newName Score:(int) newScore;@end//------  implementation ------@implementation Student@synthesize name = _name; // 让编译器帮你生成getter/setter@synthesize score = _score;/* 构造方法1 start */-(id)initWithName:(NSString *) newName{  /* 先调用父类指定的初始化方法 */  self = [super init];  /* 父类指定的初始化方法是否成功创建了父类对象? */  if(self){    // 初始化一些值    _name = newName;  }  // 返回初始化对象的新地址  return self;  }/* 构造方法1 end *//* 构造方法2 start */-(instancetype)initWithName:(NSString *) newName Score:(int) newScore{  /* 这里可以调用另一个指定的初始化方法 */  self = [this initWithName:newName];  /* 父类指定的初始化方法是否成功创建了父类对象? */  if(self){    // 初始化一些值    _score = newScore;  }  // 返回初始化对象的新地址  return self;  }/* 构造方法2 end */@end

希望通过上述代码,可以了解OC 的类是如何实例化对象的,以及了解如何自定义构造方法。这里要说明一点,按照OC 的编码习惯,构造方法名,或者叫初始化方法名,都是以init 开头的。

我们再举一个栗子,让我们的对象能够返回自己的类:

+ class   {      return self;  // 类方法返回自己} - class  {      return (id)isa;   // 实例通过isa返回类}

关于NSObject 的介绍,这里还不是很全面,接下来该说说OC 中的一些常用类型了。

未完待续。

热点阅读

网友最爱