6 OC基础06

来源:互联网 发布:长期股权投资转换知乎 编辑:程序博客网 时间:2024/05/16 04:43

6 OC基础06

特有语法

1,点语法

本质:非赋值,只是在调用set方法的时候调用set方法,在调用get方法的时候调用get方法.

  • 作用:快速调用get,set方法.
  • 语法:对象名.去掉下划线的属性名.
           p1.name = @"Rose";

注意:* 在set,get实现方法内部慎用点语法(很可能造成死循环)*,可以使用箭头调用

2,@property的使用

@property属性生成器

3,@synthesize

* 4.4之前 *
- @property作用:自动生成set,get方法的声明.

  • @synthesize作用:自动生成set,get方法的实现 (这个时候生成的属性是不带下划线的不是我们所需要的).

注意:要使用@synthesize 属性名 = _@property中的属性名.这种格式.

* 4.4之后 *

4,@property增强

@property的属性是真私有属性,只能在点语法中使用(其实是调用方法),箭头访问在外部无法看见也无法使用.

  • 实现逻辑验证可以自己重写get,set方法.
  • 不能同时重写一个属性的get,get这样会报错.
  • 不写@property:
    • 属性只用于内部访问,用自己设置的真私有属性.

重写set,get方法:

5,动态类型和静态类型(指针类型)

  • OC是一门弱语言,编译器在检查时没那么严格,很容易通过.
    弱语言的优点:自由灵活
    缺点:出了错误之后很难找.

  • 强语言优点:不自由
    缺点:提前发现错误

OC是一门动态语言,运行才会报错,编译很多都不会报错.

静态类型:ZLPerson *p1 = [ZLPerson new];

动态类型:ZLPerson *p2 = [ZLStudent new];

在OC中任意指针指向任意类型对象,最多只是警告,不会报错.(指针都是八个字节,可以储存任何对象的地址)

6,编译检查-等号左边

编译器(LLVM)在编译源代码时,检查语法错误.指针对象调用方法(找指针的类型的类有没有这个方法,没有,报错,通不过编译)可以通过强制类型转换来骗过编译器.强制类型转换以后属性可以通过get,set方法访问,但是不能通过点语法访问.

7,运行检查-等号右边

程序在运行的时候,当要调用这个指针指向的对象时,依然会做一个检查.回去检查这个指针指向的对象是否有这个方法,如果没有就报错.

所以:
1. 编译检查只是检查指针类型.
2. 运行检查是检查对象有没有这个方法,没有还是会报错.编译成功,并不代表没有问题.

8,NSObject指针

  • NSobject是所有类的基类.
    • c不是对象.
      NSObject指针可以当做万能指针.

9,id指针(内部已经加*了)

  1. id指针是一个万能指针,指向任意的对象.
  2. 区别:

    • a.当指针类型为OBJect类型时,编译器会做编译检查,可能要进行强制类型转换.

    • b.id不会编译检查(特性:直接跳过)

* 局限性:只能调用方法,不能用点语法.如果使用要进行强转 *其他类型指针(父类)也不可以用点语法,除了instancetpe返回当前对象的才可以.

以后尽量使用id代替OBJect.

10,instancetype

区别:
  1. 都能作为返回值,instancetype能精准返回对象类型返回值.

  2. id是一个万能指针,躲过编译检查,不仅可以作为方法的返回,还可以用来定义类型,instancetype则只能作为返回值.

    • 父类构造对象方法,返回值为父类的指针类型,子类调用方法,创建的是一个父类对象,怎么解决?
   当子类调用方法创建的是一个父类对象,怎么解决这个问题             + (id)person{                      return [ZLPerson new];                  }

标准的在类方法中,因为子类有可能继承这个方法,所以子类创建对象时也最好是子类的.用self创建.

   当子类调用方法用self创建对象,解决了这个问题             + (id)person{                      return [self new];                  }

但是要接受这个类创建的对象,可以用任何类型的指针去接受,这显然不合逻辑(对象可以用NSString来接受,因为返回的是一个id类型),怎么解决这个问题

    当子类调用方法创建对象用self,且返回instancetype类型,解决了这个问题             + (instancetype)person{                      return [self new];                  }    代表返回值是当前类的对象,不是任意对象了.最常规的写法

11,动态类型检测

需求:编译检查时,只是检查指针类型,希望检查这个指针指向的对象有没有这个方法.

     方法一:对象中有没有这个方法     BOOL a =[stu respondsToSelector:@selector(run)];     方法二:对象是不是某个类的对象,包括子类     BOOL b = [stu isKindOfClass:[ZLStudent class]];     方法三:对象是不是某个类成员,不包括子类     BOOL c = [stu isMemberOfClass:[ZLStudent class]];     方法二:前面类是不是后面类的子类     BOOL d = [ZLPerson isSubclassOfClass:[ZLStudent class]];         

12,构造方法

        Person *p1 = [[Person alloc]init];

注意:创建对象* 务必要初始化对象 *,因为init除了初始化,还做了另外的申请,如果为init可能将导致问题.

13,重写构造方法

- (instancetype)init{    //1,先调用父类的init方法,因为父类方法做了出了初始化之外的东西,你init仅仅给他初始化属性他的其他的东西就被你抹掉了,所以一定要重写!    //2,可能调用父类的init方法会失败,需要做判断    //3,现在才可以重写init方法了    //4,返回重写的对象.    if ([super init]) {        self.age = 18;    }    return self;}

14,自定义构造方法

- (instancetype)initWithAge:(int)age{    if ([super init]) {        self.age = 19;    }    return self;}

如果父类自定义构造方法了,子类再重写或自定义构造方法的时候,super调用的就是父类自定义构造方法,而不是[super init].

0 0