《iOS编程实战》读书笔记 24章3节

一、 使用方法签名和调用

1,NSInvocation
  
  An NSInvocation is an Objective-C message rendered static, that is, it is an action turned into an object. NSInvocation objects are used to store and forward messages between objects and between applications, primarily by NSTimer objects and the distributed objects system.

An NSInvocation object contains all the elements of an Objective-C message: a target, a selector, arguments, and the return value. Each of these elements can be set directly, and the return value is set automatically when the NSInvocation object is dispatched.

An NSInvocation object can be repeatedly dispatched to different targets; its arguments can be modified between dispatch for varying results; even its selector can be changed to another with the same method signature (argument and return types). This flexibility makes NSInvocation useful for repeating messages with many arguments and variations; rather than retyping a slightly different expression for each message, you modify the NSInvocation object as needed each time before dispatching it to a new target.

NSInvocation does not support invocations of methods with either variable numbers of arguments or union arguments. You should use the invocationWithMethodSignature: class method to create NSInvocation objects; you should not create these objects using alloc and init.

This class does not retain the arguments for the contained invocation by default. If those objects might disappear between the time you create your instance of NSInvocation and the time you use it, you should explicitly retain the objects yourself or invoke the retainArguments method to have the invocation object retain them itself.

这是文档中给的解释。
2,简单的demo。

  SEL initSel = @selector(init);

  SEL allocSel = @selector(alloc);

  NSMethodSignature *initSig, *allocSig;

  //从实例中请求实例方法签名

  initSig = [@"String" methodSignatureForSelector:initSel];

  //从类中请求实例方法签名

  initSig = [NSString instanceMethodSignatureForSelector:initSel];

  //从类中请求实例方法签名

  allocSig = [NSString methodSignatureForSelector:allocSel];

总结:从实例中与从类中获取到的方法签名是相同的。

NSMutableSet *set = [NSMutableSet set];

NSString *stuff = @"Stuff";

SEL selector = @selector(addObject:);

NSMethodSignature *sig = [set methodSignatureForSelector:selector];

NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig];

[invocation setTarget:set];

[invocation setSelector:selector];

[invocation setArgument:&stuff atIndex:2];

[invocation invoke];

3,蹦床
  蹦床把一条消息从一个对象“反弹”到里一个对象。这种技术允许一个代理对象把消息转移到另一个线程、缓存结果、合并重复的消息或者任何其他中间配置。蹦床一般使用forwardInvocation方法处理消息。如果一个对象在Objective-C提示错误之前不响应一个选择器,它就会创建一个NSInvocation并且传递给该对象的forwardInvocation:方法。你可以用它以任何方式转发消息。在下面这个示例中,你将创建一个叫RNObserverManager的蹦床。任何发送到trampoline(蹦床)的信息都将被转发到响应选择器的已注册的观察者。
  我的理解:就是发送到蹦床的方法,蹦床都会找已经注册的观察者是不是可以响应发送到蹦床的方法,如果响应了就执行,也就是有100个观察者,可能同时100个观察者调用这个方法(上面的话这句话我理解了好久),实现了类似于通知的功能,当观察者较多的时候速度比较快,个人认为可以理解下这样的思路,在实际应用中并不常见,以下是蹦床代码。

// RNObserverManager.h
#import <Foundation/Foundation.h>
#import <objc/runtime.h>

@interface RNObserverManager : NSObject
- (id)initWithProtocol:(Protocol *)protocol observers:(NSSet          *)observers;
- (void)addObserver:(id)observer;
- (void)removerObserber:(id)observer;
@end


//RNObserverManager.m
#import "RNObserverManager.h"
@interface RNObserverManager()
@property(nonatomic,readonly,strong)NSMutableSet *observers;
@property(nonatomic,readonly,strong)Protocol *protocol;
@end
@implementation RNObserverManager
- (id)initWithProtocol:(Protocol *)protocol observers:(NSSet *)observers{

if (self = [super init]) {
    
    _protocol = protocol;
    
    _observers = [NSMutableSet setWithSet:observers];
}

return self;

}
- (void)addObserver:(id)observer{

    NSAssert([observer conformsToProtocol:self.protocol],@"Observer must conform to protocol.");
    [self.observers addObject:observer];
}

- (void)removerObserber:(id)observer{

    [self.observers removeObject:observer];
}
-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{

  //检查蹦床本身
  NSMethodSignature *result = [super methodSignatureForSelector:aSelector];

  if (result) {
    
      return result;
  }    


  //查找所需方法
  struct objc_method_description desc = protocol_getMethodDescription(self.protocol, aSelector, YES, YES);

if (desc.name == NULL) {
    
    //找不到  也许他是可选的
      desc = protocol_getMethodDescription(self.protocol, aSelector, NO, YES);
  }

  if (desc.name == NULL) {
    
      //找不到,抛出异常NSInvalidArgumentException
      [self doesNotRecognizeSelector:aSelector];
    
      return nil;
  }

  return [NSMethodSignature signatureWithObjCTypes:desc.types];


 }

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

  SEL selector = [anInvocation selector];

  for (id responder in self.observers) {
    
      if ([responder respondsToSelector:selector]) {
        
          [anInvocation setTarget:responder];
        
          [anInvocation invoke];
        }
    }
}

@end

蹦床的使用1:

//ViewController.h
#import <UIKit/UIKit.h>
#import "RNObserverManager.h"
@protocol MyProtocol <NSObject>

- (void)doSomething;

@end
@interface ViewController : UIViewController<MyProtocol>
@property(nonatomic,strong)NSMutableSet *observers;

@end
//ViewController.m
#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    _observers = [NSMutableSet set];

    [_observers addObject:self];

    id observerManager = [[RNObserverManager alloc]initWithProtocol:@protocol(MyProtocol) observers:_observers];

    [observerManager doSomething];

}
- (void)doSomething{

    NSLog(@"doSomthing");

}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

蹦床的使用2:

//  RNMainThreadTrampoline.h

#import <Foundation/Foundation.h>

@interface RNMainThreadTrampoline : NSObject
@property(nonatomic,readwrite,strong)id target;
- (id)initWithTarget:(id)atarget;
@end

//  RNMainThreadTrampoline.m

#import "RNMainThreadTrampoline.h"

@implementation RNMainThreadTrampoline
-(id)initWithTarget:(id)atarget{

    if (self = [super init]) {
    
        _target = atarget;
    }
return self;

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

    return [self.target methodSignatureForSelector:aSelector];

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

    [anInvocation setTarget:self.target];
    [anInvocation retainArguments];
    [anInvocation performSelectorOnMainThread:@selector(invoke) withObject:nil waitUntilDone:NO];

}
@end

解释:forwardInvocation:方法可以自如地合并重复消息、添加记录、将消息转发到其他机器,并且执行多种功能。
问题:这是一个可以将所有消息转发给主线程的蹦床,那具体的使用场景是什么呢?

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容

  • **2014真题Directions:Read the following text. Choose the be...
    又是夜半惊坐起阅读 9,380评论 0 23
  • 前文再续,书接上一回!在昨天的收盘点评《生蚝说:圆弧构造的思考》中,我讲到:“ 1,假如在5月12号前,指数已...
    果园生蚝阅读 1,074评论 0 1
  • 一位朋友 如果不是他自己说起 我们也无法从 他西装革履的打扮知道 他刚坐了牢出来 有天晚上已经很晚了 我有点事去找...
    吻章阅读 66评论 0 0
  • 这几天阳光正好,我闲来无事就想着把屋后那一块空地整理出来,种点小白菊,种点时令蔬菜。 其实从回来乡下开始,一直都特...
    默默huangjuan阅读 656评论 21 8
  • 昨晚洗漱完毕躺在床上正准备写感赏日记,打开简书首页看到一篇文章的题目《“我愿意为了孩子去死”“请你先把手机放下”》...
    旦子阅读 140评论 0 2