NSObject

来源:互联网 发布:旗宇cms网站管理系统 编辑:程序博客网 时间:2024/05/16 18:21

NSObject

+ (void)initialize;

+ (void)load;    

initialize方法在第一次给某个类发送消息时调用(比如实例化一个对象),并且只会调用一次。initialize方法实际上是一种惰性调用,也就是说如果一个类一直没被用到,那它的initialize方法也不会被调用,这一点有利于节约资源。

load方法在这个文件被程序装载时调用。只要是在Compile Sources中出现的文件总是会被装载,这与这个类是否被用到无关,因此load方法总是在main函数之前调用。

总结:

1.loadinitialize方法都会在实例化对象之前调用,以main函数为分水岭,前者在main函数之前调用,后者在之后调用。这两个方法会被自动调用,不能手动调用它们。

2.loadinitialize方法都不用显示的调用父类的方法而是自动调用,即使子类没有initialize方法也会调用父类的方法,而load方法则不会调用父类

3.load方法通常用来进行Method Swizzleinitialize方法一般用于初始化全局变量或静态变量。

4.loadinitialize方法内部使用了锁,因此它们是线程安全的。实现时要尽可能保持简单,避免阻塞线程,不要再使用锁。


+ (instancetype)alloc;

+ (instancetype)allocWithZone:(struct _NSZone *)zone;

使用alloc方法创建一个类的实例的时候,其实最后还是会调用 allocWithZone方法。在OCallocWithZone这个方法应该是弃用了的,只是由于历史原因苹果还保留着这个函数。一切起源于Apple官方文档里面关于单例(Singleton)的示范代码。


- (instancetype)init;

初始化的对象


- (id)copy;

- (id)mutableCopy;

+ (id)copyWithZone:(struct _NSZone *)zone OBJC_ARC_UNAVAILABLE;

+ (id)mutableCopyWithZone:(struct _NSZone *)zone OBJC_ARC_UNAVAILABLE;

             

HSPerson *p = [[HSPerson alloc] init];

p.age = 20;

p.height = 170.0;

HSPerson *copyP = [p copy];

//<NSCopying>

- (id)copyWithZone:(NSZone *)zone

{

    HSPerson *person = [[HSPerson allocWithZone:zone] init];

    return person;

    // 有些人可能下面alloc,重新初始化空间,但这方法已给你分配了zone,自己就无需再次alloc内存空间了

    // HSPerson *person = [[HSPerson alloc] init];

}

- (id)mutableCopyWithZone:(NSZone *)zone

{

    HSPerson *person = [[HSPerson allocWithZone:zone] init];

    person.age = self.age;

    person.height = self.height;

      return person;

}


@property (nonatomic, copy) NSString *name; property copy实际上就对name干了这个:

- (void)setName:(NSString *)name

{

    _name = [name copy];

  }


- (void)dealloc;

对象销毁后自动调用


- (instancetype)init;

分配接收类的新实例,发送一条init消息,并返回已初始化的对象。



+ (Class)class;

+ (Class)superclass;

+ (BOOL)isSubclassOfClass:(Class)aClass;

返回一个布尔值,该值指示接收类是否为给定类的子类或与之相同。


+ (BOOL)instancesRespondToSelector:(SEL)aSelector;

判断一个实例变量是否能够调用一个类的方法

比如,

BOOL boolValue = [NSArray instancesRespondToSelector:@selector(initWithArray:)];返回YES;

BOOL boolValue = [NSArray instancesRespondToSelector:@selector(arrayWithArray:)];返回NO


- (BOOL)conformsToProtocol:(Protocol *)aProtocol;

判断一个接收者是否能够遵从一个给定的protocol。一个接收者遵从一个协议,可以是直接接受这个协议,也可以继承一个已经接受这个协议的类。


- (BOOL)isProxy;

判断一个实例不继承自NSObject,如果返回NO就是继承自NSObject,反之返回YES


- (IMP)methodForSelector:(SEL)aSelector;

定位并且返回接收者实现该方法的地址,因此可以作为一个方法来调用。


+ (IMP)instanceMethodForSelector:(SEL)aSelector;

      SEL只是方法编号,IMP是一个函数指针,保存了方法的地址

      为什么不直接获得函数指针,而要从SEL这个编号走一圈再回到函数指针呢?

      有了SEL这个中间过程,我们可以对一个编号和什么方法映射做些操作,也就是说我们可以一个SEL指向不同的函数指针,这样就可以完成一个方法名在不同时候执行不同的函数体

    //方法编号

    SEL methodId=@selector(func1);

    //执行对应方法可以用respondsToSelector: 这个方法提前判断。

    [selfperformSelector:methodIdwithObject:nil];

   //通过编号获取方法名

    NSString*methodName =NSStringFromSelector(methodId);

    //IMP获得和使用

    IMP methodPoint = [selfmethodForSelector:methodId];

    methodPoint();

+ (NSMethodSignature *)instanceMethodSignatureForSelector:(SEL)aSelector;

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;

performSelector:withObject:函数可以直接调用这个消息。但是perform相关的这些函数,有一个局限性,其参数数量不能超过2个,否则要做很麻烦的处理,与之相对,NSInvocation也是一种消息调用的方法,并且它的参数没有限制。这两种直接调用对象消息的方法,在IOS4.0之后,大多被block结构所取代,只有在很老的兼容性系统中才会使用。


消息转发


方案一:

+ (BOOL)resolveClassMethod:(SEL)sel;

+ (BOOL)resolveInstanceMethod:(SEL)sel;

void eat(id dd,SEL aa) {

    NSLog(@"dog eat %@%s",dd,aa);

}

//处理未实现的方法,sel添加方法实现

+(BOOL)resolveInstanceMethod:(SEL)sel {

    if (sel == @selector(eat)) {

        class_addMethod(self, sel, (IMP)eat,"v@:");

        return YES;

    }

    return [superresolveInstanceMethod:sel];

}


方案二:

- (id)forwardingTargetForSelector:(SEL)aSelector

//cat对象找有没有eat方法

-(id)forwardingTargetForSelector:(SEL)aSelector {
    return [[Catalloc]init];

}



方案三:

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;

+ (NSMethodSignature *)instanceMethodSignatureForSelector:(SEL)aSelector;

- (void)forwardInvocation:(NSInvocation *)anInvocation;

//创建一个函数签名,这个签名可以是任意的,但需要注意,签名函数的参数数量要和调用的一致。

-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {

    if (aSelector ==@selector(eat)) {

        SEL sss =@selector(run:pram:pram:);

        NSMethodSignature *sig = [CatinstanceMethodSignatureForSelector:sss];

        return sig;

    }

    return [supermethodSignatureForSelector:aSelector];

}

//将消息转出某对象

-(void)forwardInvocation:(NSInvocation *)anInvocation {

    if (anInvocation.selector ==@selector(eat)) {

        Cat *cat = [[Catalloc]init];

        SEL sss =@selector(run:pram:pram:);

        NSString *a =@"a";

        NSString *b =@"b";

        NSString *c =@"c";

        [anInvocation setTarget:cat];

        [anInvocation setSelector:sss];

        [anInvocation setArgument:&aatIndex:2];

        [anInvocation setArgument:&batIndex:3];

        [anInvocation setArgument:&catIndex:4];

        if ([cat respondsToSelector:sss]) {

            [anInvocation invoke];

        }

    }

}