美文网首页
利用消息转发解决对NSNull对象操作导致的崩溃

利用消息转发解决对NSNull对象操作导致的崩溃

作者: 逆光少年 | 来源:发表于2017-08-29 20:02 被阅读47次
    消息转发,适用于把操作给另外一个类来实现
    -(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
    {
        NSMethodSignature *signature = [super methodSignatureForSelector:aSelector];
        if (!signature) {
            signature = [self.displayLabel methodSignatureForSelector:aSelector];
        }
        return signature;
    }
    
    -(void)forwardInvocation:(NSInvocation *)anInvocation
    {
        SEL selector = [anInvocation selector];
        if ([self.displayLabel respondsToSelector:selector]) {
            [anInvocation invokeWithTarget:self.displayLabel];
        }
    }
    

    下面例子中,一个UIViewController包含了UIlable 属性 displayLabel, 如果UIViewController 实例调用[instance setText:@"string"]方法,由于类没有实现setText:方法,通过上面两行代码,将会转发,由 displayLabel 实现。

    #import "RootVC.h"
    
    @interface RootVC ()
    
    @end
    
    @implementation RootVC
    
    - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
    {
        self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
        if (self) {
            // Custom initialization
        }
        return self;
    }
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        
        self.title = @"Root";
        
        [self addButton];
        // Do any additional setup after loading the view.
    }
    
    -(void)addButton
    {
        UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
        btn.frame = CGRectMake(20.0, 100.0, 100.0, 40.0);
        [btn setTitle:@"Next" forState:UIControlStateNormal];
        [btn setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
        [btn addTarget:self action:@selector(naviNext) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:btn];
        
        UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(20.0, 140.0, 200.0, 30.0)];
        self.displayLabel = label;
        [self.view addSubview:label];
        [label release];
     
        [self setText:@"你好"]; //这里setText是不能被自己接受的,但是应为在下面做了消息转发,最后事件由self.displayLabel 接受了
    }
    
    -(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
    {
        NSMethodSignature *signature = [super methodSignatureForSelector:aSelector];
        if (!signature) {
            signature = [self.displayLabel methodSignatureForSelector:aSelector];
        }
        return signature;
    }
    
    -(void)forwardInvocation:(NSInvocation *)anInvocation
    {
        SEL selector = [anInvocation selector];
        if ([self.displayLabel respondsToSelector:selector]) {
            [anInvocation invokeWithTarget:self.displayLabel];
        }
    }
    
    
    -(void)naviNext
    {
       
    }
    
    - (void)didReceiveMemoryWarning
    {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    @end
    
    下面是封装的分类
    //
    //  TestController.m
    //  0803test
    //
    //  Created by Xudongdong on 2017/8/29.
    //  Copyright © 2017年 Xudongdong. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    
    @interface NSNull (InternalNullExtention)
    
    @end
    
    //
    //  TestController.m
    //  0803test
    //
    //  Created by Xudongdong on 2017/8/29.
    //  Copyright © 2017年 Xudongdong. All rights reserved.
    //
    
    //来源于 http://blog.rpplusplus.me/blog/2014/03/28/nsnull-category/
    
    #define NSNullObjects @[@"",@0,@{},@[]]
    
    #import "NSNull+InternalNullExtention.h"
    
    @implementation NSNull (InternalNullExtention)
    
    - (NSMethodSignature*)methodSignatureForSelector:(SEL)selector
    {
        NSMethodSignature* signature = [super methodSignatureForSelector:selector];
        if (!signature) {
            for (NSObject *object in NSNullObjects) {
                signature = [object methodSignatureForSelector:selector];
                if (signature) {
                    break;
                }
            }
            
        }
        return signature;
    }
    
    - (void)forwardInvocation:(NSInvocation *)anInvocation
    {
        SEL aSelector = [anInvocation selector];
        
        for (NSObject *object in NSNullObjects) {
            if ([object respondsToSelector:aSelector]) {
                [anInvocation invokeWithTarget:object];
                return;
            }
        }
        
        [self doesNotRecognizeSelector:aSelector];
    }
    
    
    @end
    

    相关文章

      网友评论

          本文标题:利用消息转发解决对NSNull对象操作导致的崩溃

          本文链接:https://www.haomeiwen.com/subject/kmradxtx.html