NSProxy的簡單使用

平時(shí)開發(fā)中我們使用的大部分類的基類都是NSObject,今天介紹另一個(gè)基類——NSProxy。
先來看一下蘋果官方文檔:

NSProxy

An abstract superclass defining an API for objects that act as stand-ins for other objects or for objects that don’t exist yet.
好的轩褐,我們知道了他是一個(gè)抽象類。
再往下

Overview

Typically, a message to a proxy is forwarded to the real object or causes the proxy to load (or transform itself into) the real object. Subclasses of NSProxy
can be used to implement transparent distributed messaging (for example, NSDistantObject
) or for lazy instantiation of objects that are expensive to create.
NSProxy
implements the basic methods required of a root class, including those defined in the NSObject
protocol. However, as an abstract class it doesn’t provide an initialization method, and it raises an exception upon receiving any message it doesn’t respond to. A concrete subclass must therefore provide an initialization or creation method and override the forwardInvocation:
and methodSignatureForSelector:
methods to handle messages that it doesn’t implement itself. A subclass’s implementation of forwardInvocation:
should do whatever is needed to process the invocation, such as forwarding the invocation over the network or loading the real object and passing it the invocation. methodSignatureForSelector:
is required to provide argument type information for a given message; a subclass’s implementation should be able to determine the argument types for the messages it needs to forward and should construct an NSMethodSignature
object accordingly. See the NSDistantObject
, NSInvocation
, and NSMethodSignature
class specifications for more information.
原來朋其,它的作用是一個(gè)映射括授,通過定義子類,并重寫

- (void)forwardInvocation:(NSInvocation *)anInvocation;
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel;

這兩個(gè)方法來實(shí)現(xiàn)將消息轉(zhuǎn)發(fā)給真正的對象踏拜。我們知道OC不支持多繼承碎赢,通過NSProxy,就可以模擬實(shí)現(xiàn)多繼承速梗。那么現(xiàn)在肮塞,NSProxy怎么用呢?

假設(shè)現(xiàn)在有這樣一個(gè)需求:
我們已經(jīng)將項(xiàng)目中的網(wǎng)絡(luò)接口進(jìn)行了模塊化姻锁,將不同模塊下的接口放在了不同的文件中枕赵。當(dāng)我們想調(diào)用不同模塊下的接口時(shí),想要通過一個(gè)統(tǒng)一的映射來調(diào)用屋摔,現(xiàn)在我們來寫這個(gè)映射烁设。
首先,我們來創(chuàng)建兩個(gè)接口模塊钓试。
商品模塊:

@protocol ProductServiceProtocel <NSObject>
- (void)getProductInfo:(NSString *)productSkn;
@end

@interface ProductService : NSObject
@end

以及訂單模塊:

@protocol OrderServiceProtocel <NSObject>
- (void)submitOrder:(NSString *)prodcutName;
@end

@interface OrderService : NSObject
@end
注意:這里的接口聲明要寫在protocol中,然后讓我們的proxy遵循這兩個(gè)協(xié)議副瀑,用來騙過編譯器弓熏。

然后我們實(shí)現(xiàn)這兩個(gè)接口模塊:

@implementation ProductService
- (void)getProductInfo:(NSString *)productSkn {
    NSLog(@"我是一件程序員標(biāo)配的橫條紋T,我的skn是%@",productSkn);
}
@end
@implementation OrderService
- (void)submitOrder:(NSString *)prodcutName {
    NSLog(@"我買了一件%@",prodcutName);
}
@end

現(xiàn)在我們來寫我們的映射糠睡。

#import <Foundation/Foundation.h>
#import "ProductService.h"
#import "OrderService.h"

@interface ServiceProxy : NSProxy <ProductServiceProtocel, OrderServiceProtocel>
+ (ServiceProxy *)shareProxy;
@end

NSProxy是一個(gè)抽象類挽鞠,系統(tǒng)不提供init方法,所以需要我們自己實(shí)現(xiàn)。

#import "ServiceProxy.h"
#import <objc/runtime.h>

@implementation ServiceProxy
{
    ProductService *_product;
    OrderService *_order;
    NSMutableDictionary *_targetProxy;
}

#pragma class method
+ (ServiceProxy *)shareProxy {
    return [[ServiceProxy alloc] init];
}

#pragma init
- (ServiceProxy *)init {
    _targetProxy = [NSMutableDictionary dictionary];
    _product = [[ProductService alloc] init];
    _order = [[OrderService alloc] init];
    
    [self _registerMethodsWithTarget:_product];
    [self _registerMethodsWithTarget:_order];
    
    return self;
}

在init方法中信认,初始化成員變量已經(jīng)將各接口模塊中的方法以及對象映射在一個(gè)字典中材义。

#pragma private
- (void)_registerMethodsWithTarget:(id)target {
    unsigned int methodsNum = 0;
    
    Method *methodList = class_copyMethodList([target class], &methodsNum);
    for (int i = 0; i < methodsNum; i++) {
        Method method = methodList[i];
        SEL temp_sel = method_getName(method);
        const char *temp_method_name = sel_getName(temp_sel);
        [_targetProxy setObject:target forKey:[NSString stringWithUTF8String:temp_method_name]];
    }
    
    free(methodList);
}

接下來就可以重寫系統(tǒng)提供的兩個(gè)方法,根據(jù)方法名從我們的映射字典中找到對應(yīng)的target嫁赏,然后執(zhí)行其掂。

#pragma override
- (void)forwardInvocation:(NSInvocation *)invocation {
    SEL selector = invocation.selector;
    NSString *methodName = NSStringFromSelector(selector);
    id target = _targetProxy[methodName];
    if (target && [target respondsToSelector:selector]) {
        [invocation invokeWithTarget:target];
    }else {
        [super forwardInvocation:invocation];
    }
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
    NSString *methodName = NSStringFromSelector(sel);
    id target = _targetProxy[methodName];
    if (target && [target respondsToSelector:sel]) {
        return [target methodSignatureForSelector:sel];
    }else {
        return [super methodSignatureForSelector:sel];
    }
}

現(xiàn)在服務(wù)映射就寫完了,在控制器中來調(diào)動(dòng)接口:

ServiceProxy *proxy = [ServiceProxy shareProxy];
[proxy getProductInfo:@"123456"];
[proxy submitOrder:@"程序員標(biāo)配的橫條紋T"];

最終的執(zhí)行結(jié)果:demo

image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末潦蝇,一起剝皮案震驚了整個(gè)濱河市款熬,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌攘乒,老刑警劉巖贤牛,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異则酝,居然都是意外死亡殉簸,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進(jìn)店門沽讹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來喂链,“玉大人,你說我怎么就攤上這事妥泉⊥治ⅲ” “怎么了?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵盲链,是天一觀的道長蝇率。 經(jīng)常有香客問我,道長刽沾,這世上最難降的妖魔是什么本慕? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮侧漓,結(jié)果婚禮上锅尘,老公的妹妹穿的比我還像新娘。我一直安慰自己布蔗,他們只是感情好藤违,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著纵揍,像睡著了一般顿乒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上泽谨,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天璧榄,我揣著相機(jī)與錄音特漩,去河邊找鬼。 笑死骨杂,一個(gè)胖子當(dāng)著我的面吹牛涂身,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播搓蚪,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼蛤售,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了陕凹?” 一聲冷哼從身側(cè)響起悍抑,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎杜耙,沒想到半個(gè)月后搜骡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡佑女,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年记靡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片团驱。...
    茶點(diǎn)故事閱讀 38,716評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡摸吠,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出嚎花,到底是詐尸還是另有隱情寸痢,我是刑警寧澤,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布紊选,位于F島的核電站啼止,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏兵罢。R本人自食惡果不足惜献烦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望卖词。 院中可真熱鬧巩那,春花似錦、人聲如沸此蜈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽舶替。三九已至令境,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間顾瞪,已是汗流浹背舔庶。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留陈醒,地道東北人惕橙。 一個(gè)月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像钉跷,于是被迫代替她去往敵國和親弥鹦。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評論 2 350

推薦閱讀更多精彩內(nèi)容