iOS学习笔记一

文章目录

      • 一、深浅拷贝
      • 二、消息转发机制
      • 三、运行时添加一个类

一、深浅拷贝

浅拷贝只是将指针赋值,而深拷贝进行了内容传递,在Objective-C中,NSObject的拷贝方式有两种:copy和mutablecopy;

对于NSString,NSArray这类不可变对象:

(1)使用copy得到的结果为浅拷贝,个人理解为:由于这类对象不能更改,它们在内存中存储的形式都是一致的,因此copy操作没有必要重新分配空间来存储;

(2)使用mutablecopy得到的结果为深拷贝,以NSString为例,当发生mutablecopy,得到的返回值类型为NSMutableString,因此需要在内存中重新分配空间进行存储;

对于NSMutableString、NSMutableArray这类可变对象,使用copy或者mutablecopy,都是在进行深拷贝;

以NSDictionary为例,进行深拷贝;

NSDictionary* copyWith(NSDictionary* dic) {
    
    NSMutableDictionary* result = [[NSMutableDictionary alloc] init];
    
    for (NSString* i in [dic allKeys]) {
        id copyValue = [i mutableCopy];
        
        [result setObject:copyValue forKey:i];
    }
    
    return result;
}

二、消息转发机制

在OC中,消息转发机制如下,通过重写函数,可以实现selector not found防护;

iOS学习笔记一_第1张图片

(1) 重写resolveInstanceMethod

在运行时添加未声明的方法,然后再执行;

+ (BOOL)resolveInstanceMethod:(SEL)sel
{
    
    if (sel == @selector(run)) {
        class_addMethod(self, sel, (IMP)run, @encode(NSNumber*(*)(id self, SEL _cmd, id i)));
        return YES;
    }
    
    return [super resolveInstanceMethod:sel];
    
}

通过class_addMethods,手动添加类方法,然后return YES,重新执行;

(2)重写towardingTargetForSelector

采用重定向的方式,由其他具有这个方法的对象来执行该方法;

- (id) forwardingTargetForSelector:(SEL)aSelector
{
    if (aSelector == @selector(identifier)) {
        return _people;
    }
    
    return nil;
}

(3) 重写fowardInvocation方法

首先重写methodSignatureForSelector,生成函数签名,记录了这个函数的返回类型,调用者类型,参数类型等信息,以便寄存器操作,然后重写fowardInvocation方法,直接执行;

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
    if (aSelector == @selector(foo)) {
        
        return [NSMethodSignature signatureWithObjCTypes:"v@:"];
        
    }
    
    return [super methodSignatureForSelector:aSelector];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    if ( [_people respondsToSelector: [anInvocation selector]] ) {
        [anInvocation invokeWithTarget: _people];
    }
}

执行代码:

@interface People : NSObject
-(void) identifier;
@end

@implementation People

-(void) identifier {
    NSLog(@"\nCalled by People.\n");
}

-(void) foo {
    
    NSLog(@"\nfoo!\n");
}

@end


@interface Dog: NSObject
@property (nonatomic, retain) People* people;
@property (nonatomic, retain) NSString* str1;
@end

@implementation Dog

- (instancetype)init
{
    _people = [[People alloc] init];
    _str1 = [[NSString alloc] init];
    return self;
}

+ (Dog*) deepCopy: (Dog*)aDog
{
    Dog* result = [[Dog alloc] init];
    
    [result setValue:[[People alloc] init] forKey:@"people" ];
    [result setValue:[ [aDog str1] mutableCopy] forKey: @"str1"];
    
    return result;
}

- (void) eat
{
    NSLog(@"\ncalled by Dog\n");
}

- (id) forwardingTargetForSelector:(SEL)aSelector
{
    if (aSelector == @selector(identifier)) {
        return _people;
    }
    
    return nil;
}

+ (BOOL)resolveInstanceMethod:(SEL)sel
{
    
    if (sel == @selector(run)) {
        class_addMethod(self, sel, (IMP)run, @encode(NSNumber*(*)(id self, SEL _cmd, id i)));
        return YES;
    }
    
    return [super resolveInstanceMethod:sel];
    
}

- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    if ( [_people respondsToSelector: [anInvocation selector]] ) {
        [anInvocation invokeWithTarget: _people];
    }
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
    if (aSelector == @selector(foo)) {
        
        return [NSMethodSignature signatureWithObjCTypes:"v@:"];
        
    }
    
    return [super methodSignatureForSelector:aSelector];
}

@end

......

Dog* dog = [[Dog alloc] init];

[dog performSelector:@selector(eat)];
[dog performSelector:@selector(identifier)];
[dog performSelector:@selector(run) withObject:[NSNumber numberWithInt:1]];
[dog performSelector:@selector(foo)];

三、运行时添加一个类

    // 练习用Runtime新增一个类

    Class myClass = objc_allocateClassPair([NSObject class], "MyClass", 0);

    class_addIvar(myClass, "var1", sizeof(NSString*), 0, @encode(NSString *));
    class_addMethod(myClass, @selector(run), (IMP)run, @encode(NSNumber*(*)(id self, SEL _cmd, id i)) );
    
    id myObj = [[myClass alloc] init];
    
    [myObj setValue:@"123" forKey:@"var1"];

    
    return 0;

记录点:

(1)使用objc_allocateClassPair,新增一个类;

(2)使用class_addIvar,添加类的成员变量;

(3)使用ckass_addMethod,添加成员方法;

(4)在class_addMethod中,使用@encode,根据方法格式,生成函数签名;

(5)使用performSelector执行方法时,返回值必须为NSObject类型,这是由它的声明决定的;

- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;

你可能感兴趣的:(秃秃的实习生)