1. 程式人生 > >ios 呼叫私有方法的幾種方式

ios 呼叫私有方法的幾種方式

// 獲取例項方法
- (void)getMethods
{
    int outCount = 0;
    Person *p = [Person new];
    Method *methods = class_copyMethodList([p class], &outCount);
    for (int i = 0; i < outCount; i ++) {
        NSLog(@"=============%d", i);
        // 獲取方法名
        Method method = methods[i];
        SEL methodName = method_getName(method);
        NSLog(@"方法名= %@", NSStringFromSelector(methodName));
        
        // 獲取引數
        char argInfo[512] = {};
        unsigned int argCount = method_getNumberOfArguments(method);
        for (int j = 0; j < argCount; j ++) {
            // 引數型別
            method_getArgumentType(method, j, argInfo, 512);
            NSLog(@"引數型別= %s", argInfo);
            memset(argInfo, '\0', strlen(argInfo));
        }
        
        // 獲取方法返回值型別
        char retType[512] = {};
        method_getReturnType(method, retType, 512);
        NSLog(@"返回型別值型別= %s", retType);
    }
    free(methods);
}

呼叫方式:

1. 使用  performSelector  下面2和3行結果一樣。這樣比使用物件直接呼叫好處是編譯器不會報錯,也不用方法暴露標頭檔案。

1 Person *p = [Person new];
2 [p performSelector:@selector(eat)]; // log: xxx eat====
3 [p performSelector:NSSelectorFromString(@"eat")]; // log: xxx eat====

2. 使用 objc_msgSend ,對比上面 objc_msgSend 好處是傳遞多個引數時更為方便

Person *p = [Person new]; // 需要引用 Person.h 標頭檔案
objc_msgSend(p, @selector(eat:str2:str3:), @"1", @"2", @"3"); // log: eat====1==2==3

3. 利用函式實現IMP,IMP型別結構與objc_msgSend底層是同一型別,與2中實現無差別

Person *p = [Person new];
IMP imp = [p methodForSelector:@selector(eat)];
void (* tempFunc)(id target, SEL) = (void *)imp;
tempFunc(p, @selector(eat)); // log: xxx eat====

4. 使用類物件傳送訊息,上面3種方式都需要引用 Person.h 標頭檔案,這裡類物件進行呼叫可以解決這個問題

Class pClassObj = NSClassFromString(@"Person");
objc_msgSend([pClassObj new], @selector(eat));

5.多引數

-(id)glt_performSelector:(SEL)selector withObject:(id)object,...NS_REQUIRES_NIL_TERMINATION;
{
    //根據類名以及SEL 獲取方法簽名的例項
    NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:selector];
    if (signature == nil) {
        NSLog(@"--- 使用例項方法呼叫 為nil ---");
        signature = [self methodSignatureForSelector:selector];
        if (signature == nil) {
            NSLog(@"使用類方法呼叫 也為nil, 此時return");
            return nil;
        }
    }
    //NSInvocation是一個訊息呼叫類,它包含了所有OC訊息的成分:target、selector、引數以及返回值。
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
    invocation.target = self;
    invocation.selector = selector;
    NSUInteger argCount = signature.numberOfArguments;
    // 引數必須從第2個索引開始,因為前兩個已經被target和selector使用
    argCount = argCount > 2 ? argCount - 2 : 0;
    NSMutableArray *objs = [NSMutableArray arrayWithCapacity:0];
    if (object) {
        [objs addObject:object];
        va_list args;
        va_start(args, object);
        while ((object = va_arg(args, id))){
            [objs addObject:object];
        }
        va_end(args);
    }
    if (objs.count != argCount){
        NSLog(@"--- objs.count != argCount! please check it! ---");
        return nil;
    }
    //設定引數列表
    for (NSInteger i = 0; i < objs.count; i++) {
        id obj = objs[i];
        if ([obj isKindOfClass:[NSNull class]]) {
            continue;
        }
        [invocation setArgument:&obj atIndex:i+2];
    }
    [invocation invoke];
    //獲取返回值
    id returnValue = nil;
    if (signature.methodReturnLength != 0 && signature.methodReturnLength) {
        [invocation getReturnValue:&signature];
    }
    return returnValue;
}
 
 

 注:

TestClass *cls = [[TestClass alloc] init];
objc_msgSend(cls, @selector(fun)); //錯誤寫法(arm64崩潰偶爾發生)
((void (*)(id, SEL))objc_msgSend)(cls, @selector(fun)); //正確寫法

//eg:

void (*glt_msgsend)(id, SEL, NSString *, NSString *) = (void (*)(id, SEL, NSString *, NSString *))objc_msgSend;
glt_msgsend(cls, @selector(eat:say:), @"123", @"456");
 

相關推薦

ios 呼叫私有方法方式

// 獲取例項方法 - (void)getMethods { int outCount = 0; Person *p = [Person new]; Method *methods = class_copyMethodList([p class], &

iOS 連線外設的方式

    聯絡人:石虎 QQ:1224614774   暱稱: 嗡嘛呢叭咪哄                         &

關於JAVA呼叫C++的方式和一些問題 UnsatisfiedLinkError

關於JAVA呼叫C++的幾種方式和一些問題 java呼叫c++有幾種方式,1.JNA方式,2,JNative 方式,3.JNI 方式。: 1.JNA方式 public interface MyCLibrary extends Library {

呼叫WebService的方式

一、概覽 方式1: HttpClient:可以用來呼叫webservie服務,也可以抓取網頁資料 版本1:HttpClient3.0.x 版本2:HttpClient4.x.x(目前最新4.5.2) 這2個版本的使用方式不一樣;變動較大

C++ 呼叫com的方式

1. 使用tlb 檔案:  #import "MyCom.tlb" CoInitialize(NULL); MyCom_iPtr ptr(__uuidof(MyCom));    //MyCom為實現類, 它實現了介面MyCom_i;    ptr->func();

iOS 執行緒同步方式

多執行緒同步目的有以下幾個方面:第一,對一段程式碼的執行進行保護,如果同時執行一段程式碼,中間的臨時變數可能會互相干擾造成結果不對;第二,對資源的保護,多個執行緒執行不同的程式碼,但是可能涉及同一個資源;第三,訊息傳遞,一個執行緒通知另外一個執行緒發生了一件事。

IOS 之資料庫 的方式

在iOS開發過程中,不管是做什麼應用,都會碰到資料儲存的問題。將資料儲存到本地,能夠讓程式的執行更加 流暢,不會出現讓人厭惡的菊花形狀,使得使用者體驗更好。下面介紹⼀一下資料儲存的方式: 1.NSKeyedArchiver:採用歸檔的形式來儲存資料,該資料物件需要遵守NSCoding協議,並且該物件對應

cxf呼叫服務的方式

客戶端匯入的包 方式一 JaxWsDynamicClientFactory clientFactory = JaxWsDynamicClientFactory.newInstance(); Client client = clientFactory.createClien

iOS 資料儲存的方式

在iOS開發過程中常用的本地化儲存有五種方式: 1.plist (XML屬性列表歸檔 NSArray\NSDictionary) 2.preference (偏好設定\NSUserDefaults) (本質還是通過plist來儲存資料,但是使用更加簡單,無需關注檔案、資料夾

iOS代碼加密的方式

red .sh 最簡 應用安全 adr 變量名 尋找 技術分享 混淆 眾所周知的是大部分iOS代碼一般不會做加密加固,因為iOS APP一般是通過AppStore發布的,而且蘋果的系統難以攻破,所以在iOS裏做代碼加固一般是一件出力不討好的事情。萬事皆有例外,不管iOS、a

iOS關於載入圖片的方式選擇

最近在開發過程中遇到一些效能優化的東西,這次來說說關於圖片載入的效能優化和選擇。 大家都知道建立UIImage常用以下幾種方式 + (nullable UIImage *)imageNamed:(NSString *)name; // load from main bundle

iOS中保證執行緒安全的方式與效能對比

一、前言 前段時間看了幾個開源專案,發現他們保持執行緒同步的方式各不相同,有@synchronized、NSLock、dispatch_semaphore、NSCondition、pthread_mutex、OSSpinLock。後來網上查了一下,發現他們的實現機制各不相同,效能也各不一

Java專案啟動時執行指定方法方式

很多時候我們都會碰到需要在程式啟動時去執行的方法,比如說去讀取某個配置,預載入快取,定時任務的初始化等。這裡給出幾種解決方案供大家參考。 1. 使用@PostConstruct註解 這個註解呢,可以在Spring載入這個類的時候執行一次。來看一下下方程式碼。

iOS 實現圖片圓角的方式

第一種方法:通過設定layer的屬性 最簡單的一種,但是很影響效能,一般在正常的開發中使用很少. UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(100, 100, 100, 10

a標籤中href呼叫js的方法

我們常用的在a標籤中有點選事件: 1. a href=”javascript:js_method();” 這是我們平臺上常用的方法,但是這種方法在傳遞this等引數的時候很容易出問題,而且javascript:協議作為a的href屬性的時候不僅會導致不必要的觸發window.onbeforeun

js裡宣告函式有方式? var abc = function(x){} 和 function abc(x){} 這兩宣告方法有什麼不同?

先後者是指函式宣告,前者是指函式表示式,他們之間的區別是後者會在程式碼執行之前被JS直譯器載入到作用域中,這樣一來就可以在程式設計時在定義函式之前呼叫這個函式,此法是有效的;而前者則是在程式碼執行到那一行時候才會有定義,此外函式表示式是建立了一個匿名函式,然後將

spring mvc 實現遠端服務呼叫方式

org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter 實現遠端服務呼叫 (1)httpinvoker方式 伺服器客戶端都是spring時推薦這種方式 服務端 必須要實現 bean實體類

iOS NSthread & Thread 開啟執行緒的方式

一、開啟執行緒執行指定物件的方法 /** 引數1: 執行引數2方法的物件 引數2: 開啟執行緒後執行的方法 引數3: 傳遞的物件資料(引數2的方法可以直接用) */ // OC - (

java呼叫webservice介面 方法

webservice的 釋出一般都是使用WSDL(web service descriptive language)檔案的樣式來發布的,在WSDL檔案裡面,包含這個webservice暴露在外面可供使用的介面。今天搜尋到了非常好的 webservice provide

Java呼叫Restful API介面方式

  2018年01月16日 22:18:40 Exceed Oneself 閱讀數:1968 摘要:最近有一個需求,為客戶提供一些Restful API 介面,QA使用postman進行測試,但是postman的測試介面與java呼叫的相似但並不相同,於是想自己