zoukankan      html  css  js  c++  java
  • iOS NSInvocation的学习

    用途:

    NSInvocation的作用和performSelector:withObject:的作用是一样的:用于iOS编程中调用某个对象的消息。

    performSelector:withObject:调用一些参数较少的消息是比较方便的,但是对于参数个数大于2的消息,使用NSInvocation还是比较方便的。

    因为NSInvocation是静态的呈现Objective-C的消息,也就是说,它把一个行动变成了一个对象。NSInvocation对象用于对象之间和应用程序之间存储和转发消息,主要通过NSTimer对象和分布式对象系统来完成。


    代码:

    //
    //  NSInvocation+Improved.h
    //  InvocationDemo
    //
    //  Created by 李振杰 on 13-12-11.
    //  Copyright (c) 2013年 swplzj. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    
    @interface NSInvocation (Improved)
    
    + (NSInvocation *)invocationWithTarget:(id)_target andSelector:(SEL)_selector;
    + (NSInvocation *)invocationWithTarget:(id)_target andSelector:(SEL)_selector andArguments:(void *)_addressOfFirstArgument, ...;
    - (void)invokeOnMainThreadWaitUntilDone:(BOOL)wait;
    
    @end
    
    //
    //  NSInvocation+Improved.m
    //  InvocationDemo
    //
    //  Created by 李振杰 on 13-12-11.
    //  Copyright (c) 2013年 swplzj. All rights reserved.
    //
    
    #import "NSInvocation+Improved.h"
    
    @implementation NSInvocation (Improved)
    
    + (NSInvocation *)invocationWithTarget:(id)_target andSelector:(SEL)_selector
    {
        //方法签名类
        //需要给定一个方法,用于必须创建一个NSInvocation对象的情况下,例如在消息的转发。
        NSMethodSignature *methodSig = [_target methodSignatureForSelector:_selector];
        //根据方法签名类来创建一个NSInvocation
        /*
         一个NSInvocation是静态的呈现Objective-C的消息,也就是说,它是一个行动变成了一个对象。 NSInvocation对象用于对象之间和在应用程序之间存储和转发消息,主要通过NSTimer对象和分布式对象系统来完成。
        */
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
        [invocation setTarget:_target];
        [invocation setSelector:_selector];
        return invocation;
    }
    
    + (NSInvocation *)invocationWithTarget:(id)_target andSelector:(SEL)_selector andArguments:(void *)_addressOfFirstArgument, ...
    {
        NSMethodSignature *methodSig = [_target methodSignatureForSelector:_selector];
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
        [invocation setTarget:_target];
        [invocation setSelector:_selector];
        //获得签名类对象的参数个数
        unsigned int numArgs = [methodSig numberOfArguments];
        //PS:atIndex的下标必须从2开始。原因:0 1 两个参数已经被target 和selector占用
        if (2 < numArgs) {
            /*
             VA_LIST 是在C语言中解决变参问题的一组宏,所在头文件:#include <stdarg.h>
             VA_START宏,获取可变参数列表的第一个参数的地址(ap是类型为va_list的指针,v是可变参数最左边的参数)
             VA_ARG宏,获取可变参数的当前参数,返回指定类型并将指针指向下一参数(t参数描述了当前参数的类型)
             VA_END宏,清空va_list可变参数列表
             */
            
            /*
             用法:
             (1)首先在函数里定义一具VA_LIST型的变量,这个变量是指向参数的指针;
             (2)然后用VA_START宏初始化刚定义的VA_LIST变量;
             (3)然后用VA_ARG返回可变的参数,VA_ARG的第二个参数是你要返回的参数的类型(如果函数有多个可变参数的,依次调用VA_ARG获取各个参数);
             (4)最后用VA_END宏结束可变参数的获取。
             */
            va_list varargs;
            
            va_start(varargs, _addressOfFirstArgument);
            [invocation setArgument:_addressOfFirstArgument atIndex:2];
            
            for (int argIndex = 3; argIndex < numArgs; argIndex++) {
                void *argp = va_arg(varargs, void *);
                [invocation setArgument:argp atIndex:argIndex];
            }
            
            va_end(varargs);
        }
        return invocation;
    }
    
    - (void)invokeOnMainThreadWaitUntilDone:(BOOL)wait
    {
        [self performSelectorOnMainThread:@selector(invoke) withObject:nil waitUntilDone:wait];
    }
    
    @end
    


    自定义类:

    //
    //  SomeClass.h
    //  InvocationDemo
    //
    //  Created by 李振杰 on 13-12-11.
    //  Copyright (c) 2013年 swplzj. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    
    @interface SomeClass : NSObject
    
    - (void)commonOperation;
    - (void)improvedOperation;
    - (void)fireTimer:(NSDictionary *)user andDate:(NSDate *)startTime;
    
    @end
    
    //
    //  SomeClass.m
    //  InvocationDemo
    //
    //  Created by 李振杰 on 13-12-11.
    //  Copyright (c) 2013年 swplzj. All rights reserved.
    //
    
    #import "SomeClass.h"
    #import "NSInvocation+Improved.h"
    
    @implementation SomeClass
    
    - (void)commonOperation
    {
        NSDate *date = [NSDate date];
        NSDictionary *user = [NSDictionary dictionaryWithObjectsAndKeys:@"value1", @"key1", nil];
        SEL method = @selector(fireTimer:andDate:);
        NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:method];
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
        [invocation setTarget:self];
        [invocation setSelector:method];
        [invocation setArgument:&user atIndex:2];
        [invocation setArgument:&date atIndex:3];
    //    [NSTimer scheduledTimerWithTimeInterval:0.1 invocation:invocation repeats:YES];
        [invocation invoke];
    }
    
    - (void)improvedOperation
    {
        //1.创建一个没有参数的NSInvocation
    //    SEL selector = @selector(fireTimer:andDate:);
    //    NSInvocation *invocation = [NSInvocation invocationWithTarget:self andSelector:selector];
        
        //2.创建带有两个参数的NSInvocation
        NSDate *date = [NSDate date];
        NSDictionary *user = [NSDictionary dictionaryWithObjectsAndKeys:@"value1", @"key1", nil];
        NSInvocation *invocation = [NSInvocation invocationWithTarget:self andSelector:@selector(fireTimer:andDate:) andArguments:&user, &date];
        [invocation invoke];
    }
    
    - (void)fireTimer:(NSDictionary *)user andDate:(NSDate *)startTime
    {
        /*
         sleep 与 sleepForTimeInterval的区别
         sleep直接让线程停掉,sleepForTimeInterval是让runLoop停掉。比如说,你有2个APP,分别是A和B,A启动B,然后去取B的进程号,如果你用sleep等B启动再去取,你会发现取不到,因为你只是把代码加到runloop里面去,而runloop并没有执行到这句,sleep就直接让系统停在那里,所以取不到,而后者就没问题,因为它是让runloop执行到这句的时候停1s
         */
        
        [NSThread sleepForTimeInterval:2];
        NSTimeInterval timeInterval = -1 * [startTime timeIntervalSinceNow];
        NSString *timeStr = [NSString stringWithFormat:@"%.2f", timeInterval];
        NSLog(@"fireTime: %@", timeStr);
    }
    
    @end
    


    调用SomeClass:

    //
    //  AppDelegate.m
    //  InvocationDemo
    //
    //  Created by 李振杰 on 13-12-11.
    //  Copyright (c) 2013年 swplzj. All rights reserved.
    //
    
    #import "AppDelegate.h"
    #import "SomeClass.h"
    
    @implementation AppDelegate
    
    - (void)dealloc
    {
        [_window release];
        [super dealloc];
    }
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
        self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
        // Override point for customization after application launch.
        
        SomeClass *some = [[SomeClass alloc] init];
        [some commonOperation];
        [some improvedOperation];
        [some release];
        
        self.window.backgroundColor = [UIColor whiteColor];
        [self.window makeKeyAndVisible];
        return YES;
    }
    
    @end
    


    Demo源码:

    此Demo源码的下载链接。









  • 相关阅读:
    BZOJ 2733 永无乡
    【重温基础】13.迭代器和生成器
    【重温基础】13.迭代器和生成器
    【重温基础】12.使用对象
    【重温基础】12.使用对象
    【重温基础】11.Map和Set对象
    【重温基础】11.Map和Set对象
    【重温基础】10.数组
    【重温基础】10.数组
    【重温基础】9.正则表达式
  • 原文地址:https://www.cnblogs.com/fuhaots2009/p/3471519.html
Copyright © 2011-2022 走看看