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

上一篇文章 java

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

  1. NSObject 是什么鬼?objective-c

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

  3. self 是什么鬼?数组

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

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

Objective-C中的类和 NSObject

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

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

初识 NSObject

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

诸如 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{

/* 初始化方法的返回值类型也能够是instancetype */

  /* 这里能够调用另外一个指定的初始化方法 */
  self = [this initWithName:newName];

  /* 父类指定的初始化方法是否成功建立了父类对象? */
  if(self){
    // 初始化一些值
    _score = newScore;
  }
  // 返回初始化对象的新地址
  return self;
  
}
/* 构造方法2 end */

@end

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

咱们再举一个栗子,让咱们的对象可以返回本身的类:

+ class   
{  
    return self;  // 类方法返回本身
} 
- class  
{  
    return (id)isa;   // 实例经过isa返回类
}

权限修饰

咱们知道 java 里是有权限修饰的: protectedpublicprivate ,这些权限在 OC 里也存在,但方法略有不一样。

对于属性来讲,OC提供了一些关键字修饰属性,默认是protected: @protected@public@private 。另外还有 @package 权限——变量在框架内为 protected,对于框架外则是私有的。

OC里,没有“包”的概念。

// ...
  {
  @public 
    int i;
  @private 
    NSString *name;
  }
  // ...

对于方法来讲, OC 并无提供权限修饰符,但能够经过声明的位置来决定方法是不是私有:若是方法声明在 *.h 文件中,就是公有,若是在 *.m 文件,则是私有。

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

未完待续。

相关文章
相关标签/搜索