Objective -C基础知识点整理笔记持续更新......

1.总结类方法和实例方法:

类方法,也称静态方法,指的是用static关键字修饰的方法此方法属类本身的方法,不属于类的某一个实例(对象)。类方法中不可直接使用实例变量。其调用方式有三种:可直接调用、类名.方法名、对象名.方法名。实例方法指的是不用static关键字修饰的方法每个实例对象都有自身的实例方法,互相独立,不共享一个。其调用方式只能是对象名.方法名。 
用修饰符static声明的方法为静态方法,不用修饰符static声明的方法为实例方法不管类生成或未生成对象,类的静态方法都可以被使用,使用格式为:类名.静态方法名。静态方法只能使用该静态方法所在类的静态数据成员和静态方法。这是因为使用静态方法时,该静态方法所在类可能还没有对象,即使有对象,由于用类名.静态方法名方式调用静态方法,静态方法没有this指针来存放对象的地址,无法判定应访问哪个对象的数据成员。在类创建对象后,实例方法才能被使用,使用格式为:对象名.实例方法名。实例方法可以使用该方法所在类的所有静态成员和实例成员

函数又叫方法(Methods)
方法Methods又可称为函数。在Objective-C 里的类可以定义两种方法。一种是实例的方法,一种是类的方法实例的方法局限于某个类的实例,也就是必须定义这个类的实例之后,才能被调用执行的方法。类的方法不需要创建实例,直接通过类的名称就可以被调用执行的方法。
定义一个方法需要:方法名(一个或者多个关键字),返回值类型,参数类型和参数名。下面这的图详细的说明了如何定义一个实例的方法,其中负号[-]表示该方法为实例的方法,该方法的名称加上各个关键字包括冒号即为[insertValue:atIndex:]
Objective-C 调用方法是通过发送消息给对应的实例对象。发送消息的方式其实是和一般的编程语言一样就是调用实例对象的方法,Objective-C独特的地方就是方法的调用是通过一个方法名+零个或多个标示符+零个或多个参数,然而一般的编程语言只需要一个方法名+零个或多个参数就可以了Objective-C 里面之所以把调用方法称为发送消息,大概是因为所有的消息发送之后都是动态传递给实例对象的并且,如果一个子类定义了一个和父类相同方法名+标示符的方法之后,子类会先收到该消息,然后选择性的是否继续将该消息传递给父类。
发送消息是通过一对方括号[]来实现的。在括号的里面,实例对象在左边,消息以及参数等的定义在右边。例如:
[anObject insertValue:anObj atIndex:1]; 
[anObject insertValue:anObj atIndex:1];

为了避免生成多余的临时变量,Objective-C 容许直接使用消息的结果。如下例:
[[anObject getArray] insertValue:[anObject getValueToInsert] atIndex:0]; 
[[anObject getArray] insertValue:[anObject getValueToInsert] atIndex:0];

类的方法,类似于静态方法(Static Function),常用于作为工厂模式中用来生成新的实例。定义的时候和实例的方法有区别的地方就是开头的符号为加号[+]。调用的类的方法和调用(Static Function)基本相同,直接通过类名就可以。


2.Category的原理以及给Category添加属性以及方法,但是不能添加成员变量的理解

添加一个属性,调用的时候崩溃了,说是找不到getter、setter方法。查了下文档发现,OC的分类允许给分类添加属性,但不会自动生成getter、setter方法。有没有解决方案呢?有,通过运行时建立关联引用

第一个参数id object, 当前对象
第二个参数const void *key, 关联的key,可以是任意类型 
第三个参数id value, 被关联的对象 
第四个参数objc_AssociationPolicy policy关联引用的规则,取值有以下几种:

关联对象不是为类\对象添加属性或者成员变量(因为在设置关联后也无法通过ivarList或者propertyList取得) ,而是为类添加一个相关的对象,通常用于存储类信息,例如存储类的属性列表数组,为将来字典转模型的方便

- (void)setSubName:(NSString *)subName
{
    objc_setAssociatedObject(self, "subname", subName, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}


- (NSString *)subName
{
    return objc_getAssociatedObject(self, "subname");
}
也可以用这个方法获取对应的属性列表可以进行kvc字典转模型

+ (NSArray *)properties {
    // 如果已经关联了,就依据key取出被关联的对象并返回
    NSArray *pList = objc_getAssociatedObject(self, propertiesKey);
    if (pList != nil) {
        return pList;
    }
    // 如果没有关联,则设置关联对象,并将对象返回
    unsigned int count = 0;
    Ivar *ivars = class_copyIvarList([self class], &count);
    
    NSMutableArray *arrayM = [NSMutableArray arrayWithCapacity:count];
    
    for (unsigned int i = 0; i < count; ++i) {
        Ivar pty = ivars[i];
        const char *cname = ivar_getName(ivars[i]);
        NSString *name = [NSString stringWithUTF8String:cname];
        NSString *key = [name substringFromIndex:1];
        [arrayM addObject:key];
    }
    free(ivars);
    objc_setAssociatedObject(self, propertiesKey, arrayM, OBJC_ASSOCIATION_COPY_NONATOMIC);
    return arrayM.copy;
}


确实有一个class_addIvar()函数用于给类添加成员变量,但是文档中特别说明:

* @note This function may only be called after objc_allocateClassPair and before      objc_registerClassPair. 

*   Adding an instance variable to an existing class is not supported.


那么为什么不能添加成员变量能,但是能添加属性和方法呢?

意思是说,这个函数只能在“构建一个类的过程中”调用。一旦完成类定义,就不能再添加成员变量了。经过编译的类在程序启动后就runtime加载,没有机会调用addIvar。程序在运行时动态构建的类需要在调用objc_registerClassPair之后才可以被使用,同样没有机会再添加成员变量。那为什么可以在类别中添加方法和属性呢?
因为方法和属性并不“属于”类实例,而成员变量“属于”类实例。我们所说的“类实例”概念,指的是一块内存区域,包含了isa指针和所有的成员变量。所以假如允许动态修改类成员变量布局,已经创建出的类实例就不符合类定义了,变成了无效对象。但方法定义是在objc_class中管理的,不管如何增删类方法,都不影响类实例的内存布局,已经创建出的类实例仍然可正常使用。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值