1. 程式人生 > >runtime獲取屬性列表,修改屬性值,新增並修改私有方法的呼叫

runtime獲取屬性列表,修改屬性值,新增並修改私有方法的呼叫

用了兩天好好的研究了一下runtime,之前初涉runtime。懵懵懂懂的瞭解runtime的強大,但是如何的強大,只是在demo中引用MJExtension的時候自動生成model,瞭解了一些。
經過一天半的研究,首先溫習了之前的獲取屬性列表。

今天想說的具體功能如題所述。主要涉及的就是獲取並修改屬性。新增並修改私有方法。

好了,首先說一下如何獲取屬性值。如果需要獲取某個屬性,我們最先需要知道你想獲取的類的名字。如果我們只有某一個類的字串,同樣可以達到目的,這也就是runtime的神奇之處。

(1)例如我們想要得到UserInfo這個類下的所有屬性。但是現在只有字串[email protected]

"UserInfo",我們可以用最常見的runtime語句去獲取到class。如下:Class UserInfo = NSClassFromString(className);這時候我們就得到了這個類。但是這時的UserInfo相當於沒有alloc的類。

(2)我們在網上有兩種方式可以獲取到屬性的name,type以及value。第一種方式如下:

- (NSArray*)getAllPropertyName//runtime獲取model所有屬性
{
    NSMutableArray* nameArray = [NSMutableArray array];
    unsigned int
count = 0; objc_property_t *property_t = class_copyPropertyList([UserInfo class], &count); for (int i=0; i<count; i++) { objc_property_t propert = property_t[i]; const char * propertyName = property_getName(propert); [nameArray addObject:[NSString stringWithUTF8String:propertyName]]; } free(property_t); return
nameArray; }

上面只是獲取到屬性名,如果想要獲取其它的東西,也可以自行查詢方法。不過目前只有這個有點用。
第二種方法如下:

    unsigned int countNum = 0;
    Ivar *members = class_copyIvarList([self.panoramView class], &countNum);
    for (int i=0; i<countNum; i++) {
        Ivar var = members[i];
        const char *memberName = ivar_getName(var);
        //屬性描述
        NSString *memberStr = [NSString stringWithFormat:@"%s",memberName];
        if ([memberStr isEqualToString:@"_advsObject"]) {
            const char * type = ivar_getTypeEncoding(var);
        }
    }

上面的方法獲取到的屬性是C的格式,需要轉變成OC,所以中間寫了一個memberStr作為媒介。

以上就是獲取屬性的方法,下面說下如何修改屬性內容。

(3)其實修改屬性的方法,很簡單,就一句話,一共有三個引數。object_setIvar(id obj, Ivar ivar, id value)
*@param obj The object containing the instance variable whose value you want to set.
* @param ivar The Ivar describing the instance variable whose value you want to set.
* @param value The new value for the instance variable.*這是官方給的解釋。

我們根據以上的三個引數,對其進行賦值,如下:object_setIvar(self.userInfo, var, @"改過的內容");
到此:屬性的修改就結束了。今天寫這篇文章,主要是為了記錄如何修改私有方法的。所以接下來才是重頭戲。

如果我們要修改某一個類庫的私有方法,當然,通過runtime都是為了修改私有方法的,畢竟非私有方法,又何必用runtime這個繁瑣的東西呢。我這裡的需求說起來還是被第三方深惡痛絕的,但是對一些技術還處在一個瓶頸,無法越過的同學們是一個福音。
我的需求就是,下載的第三方,為了防止我們濫用他們的勞動成果,也或者為了獲得一定的報酬,所以才在程式碼中封裝一個明顯的lable或者context等控制元件懸浮在view上。我就是要把他懸浮的這個控制元件遮蔽掉,或者隱藏或者remove掉,期初想用KVO,直接setvalue:hidden的,但是由於這個控制元件是私有變數,所以無法直接使用KVO訪問的。最終選擇了使用runtime修改私有方法即可。

(4)同樣我們需要知道要修改的類的名字,然後獲取該類下的所有方法。程式碼如下:

-(NSArray *)getAllMethods
{
    unsigned int count_f =0;
    //獲取方法連結串列
    Method* methodList_f = class_copyMethodList([UserInfo class],&count_f);

    NSMutableArray *methodsArray = [NSMutableArray arrayWithCapacity:count_f];

    for(int i=0;i<count_f;i++)
    {
        Method temp_f = methodList_f[i];
        //方法的呼叫地址
        IMP imp_f = method_getImplementation(temp_f);
        //方法
        SEL name_f = method_getName(temp_f);
        //方法名字串
        const char* name_s =sel_getName(method_getName(temp_f));
        //引數數量
        int arguments = method_getNumberOfArguments(temp_f);
        //返回方法的引數和返回值的描述的字串
        const char* encoding =method_getTypeEncoding(temp_f);
        NSLog(@"方法名:%@,引數個數:%d,編碼方式:%@",[NSString stringWithUTF8String:name_s],
              arguments,[NSString stringWithUTF8String:encoding]);

        NSString *methodStr = NSStringFromSelector(name_f);

        [methodsArray addObject:methodStr];

    }
    free(methodList_f);

    return methodsArray;
}

以上就是獲取的該類下的所有方法,這個時候我們就該猜了,這是一個痛苦的過程,因為我們不知道到底哪個方法是我們需要修改的。但是一般開發者命名的時候是會根據需要做的意思而命名的,我們只能這樣縮小範圍了,但是如果真的碰到了加密的方法,或者說命名方法沒有規律的,那我真的沒辦法了。只能一個一個試試了。

(5)如果我們搜尋到了方法名為:setUserName:我們需要新增方法,然後再修改這個私有方法的回撥。

-(void)laodNewMethod
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class class = [UserInfo class];
        //原來的方法
        SEL originalSelector = @selector(setUserName:);
        //新方法
        SEL swizzledSelector = @selector(setNewUserName:);
        //原來的Method
        Method originalMethod = class_getInstanceMethod(class, originalSelector);
        //新Method
        Method swizzledMethod = class_getInstanceMethod([self class], swizzledSelector);
        //新增到runtime新方法
        BOOL didAddMethod =class_addMethod(class,originalSelector,method_getImplementation(swizzledMethod),method_getTypeEncoding(swizzledMethod));
        if (didAddMethod) {
            class_replaceMethod([self class],swizzledSelector,method_getImplementation(originalMethod),method_getTypeEncoding(originalMethod));
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }


    });
}
-(void)setNewUserName:(NSString *)newUserName
{
    NSlog("這裡就是修改後的方法,每次執行都會自動跳到這裡呼叫這個方法了。")
}

以上就是所有今天關於runtime的內容

相關推薦

runtime獲取屬性列表修改屬性新增修改私有方法呼叫

用了兩天好好的研究了一下runtime,之前初涉runtime。懵懵懂懂的瞭解runtime的強大,但是如何的強大,只是在demo中引用MJExtension的時候自動生成model,瞭解了一些。 經過一天半的研究,首先溫習了之前的獲取屬性列表。 今天想說的

遍歷物件的屬性判斷屬性並且賦用來替代三元運算

public Object getQueryCriteria1(Object fullProcessDetail) throws NoSuchMethodException, InvocationTa

jQuery批量修改Name批量增加name後綴非each(不需要循環)

jquery 批量修改name背景表單字段,配置where屬性自動刷新到可查詢區域,查詢字段需增加_where後綴,響應後臺規則問題批量設置的查詢字段,必須批量增加_where後綴方可正常查詢。each循環有點麻煩,有沒有更方便的批量修改方法。調查方向就是jquery批量修改name,整個互聯網充斥的都是.a

python 字典合字典取列表轉字典

就是 nbsp 2.7 fault font ... 3.5 bsp 轉化 1、字典的合並 # 第一種 用Python的內置方法,dict與**解包的方式 >>> a = {‘name‘:1,‘b‘:2} >>> b = {‘name‘

繼續對上一頁的ecah進行 優化求一個數組的和最大最小獲取陣列中的元素3

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <style t

在Activity中獲取AsyncTask中更新progress的可用在檔案的上傳和下載同步顯示進度

public class MyAsyncTask extends AsyncTask<String, Integer, Void>{       public AsyncResponse mAsyncResponse = null;        @Over

ajax非同步問題導致資料出錯(為什麼已經修改下方程式碼卻得到的是未修改過的

看兩段程式碼://填充推薦人資訊         $('#recommenderCode').bind('blur' , function(){//焦點觸發方法             if(idnoBlurFlag){                 //填充推薦人資訊  

小程式系列課程之6事件繫結獲取元素ID頁面傳獲取資料

根據在頁面需要實現不同的跳轉和不同的頁面傳值,梳理了以下情況情況一:在小程式的開發過程中會用到動態傳參,比如根據某一個頁面傳參不同,載入不同的新的頁面(一般會用到wx:for迴圈顯示陣列,實現的功能是點選不同的元素進入不同的頁面,比如在另一個頁面載入某個元素的詳細資訊。)情況

jquery獲取ajax成功請求的返回返回給其他函式使用

//利用回撥函式把請求返回值獲取 function getAjaxVal(cb){ $.get(url,function(data){ cb(data); }) } getAjaxVal(function(data){ return data; });

在一組資料中獲取最大最小平均值的js寫法

function refreshPrice() { var rows = $("#detailDataGrid").datagrid("getRows");  //獲取當前頁的所有行 //宣告平均值、最小值、最大值 var sum = 0; var min = rows[

修改一個讓ScrollView、ListView充滿彈性

android預設的ScrollView、ListView在最頂端下拉或者最底端上拉的時候,都不會帶有反彈效果,很生硬的讓你不能繼續拖動,記得不像iOS那樣可以回彈,個人認為,iOS的互動還是略好一

獲取list中的最大最小

方法一:int max = List.get(0); int min = List.get(0); for (int i = 0; i < List.size(); i++){ if(min

循環獲取數據庫中的並存儲到集合中

red .exe class ring dst 集合 next 新的 result package com.zdy.getxxx;import java.sql.Connection;import java.sql.PreparedStatement;import java

C++筆記(11):拷貝控制(拷貝移動構造賦析構)

con 對象 構造函數 col let 拷貝控制 支持 運算符 () 控制對象拷貝,賦值,析構   拷貝構造函數,移動構造函數   拷貝賦值運算符,移動賦值運算符   析構函數 -----------------------------------------------

最大最小平均值標準差的計算

ray num 最大值 標準差 bsp div clas min 2.0 用numpy函數可實現快速計算 n [23]: import numpy as np In [24]: data = [1, 2, 3] In [25]: np.mean(data) Out[2

愛一款微信編輯器始於顏忠於人品陷於才華

優秀 操作 尋找 模式 吸引力 現在 自己的 nag 聊天 現如今,隨著科技的進步,互聯網的發展,手機 成了人手必備的交流溝通工具,而微信自然而然的占據了較大的使用率。我們使用微信聊天,看訂閱號。訂閱號裏面吸引人眼球的當屬於那些題目有吸引力,圖片精美,內容有深度的文章。 現

浮點數的最大最小精度以及儲存位元組

#include <stdio.h> #include <float.h> int main() { printf("float 儲存最大位元組數 : %lu \n", sizeof(float)); printf("float 最小值: %E\n", FLT

課堂練習--計算陣列的最大最小平均值標準差中位數;numpy.random模組提供了產生各種分佈隨機數的陣列;正態分佈;Matplotlib

#計算陣列的最大值,最小值,平均值,標準差,中位數 import numpy as np a=np.array([1, 4, 2, 5, 3, 7, 9, 0]) print(a) a1=np.max(a) #最大值 print(a1) a2=np.min(a) #最小值 print(a2) a3

JAVA——計算陣列的最大最小陣列的和數組合陣列擷取

1,計算陣列的最大值 2,計算陣列的最小值 3,計算陣列和 4,合併陣列 5,擷取陣列 public class ArrayEvent{ //1,計算陣列中的最大值 public static int arrMax(int[] arr1){ if(arr1 == null){

當實體類中entity/DTO/VO等類中有列舉應該怎麼輸出?

當實體類中entity/DTO/VO等類中,有列舉值,應該怎麼輸出? 問題: orderStatus 和 payStatus都是列舉類,並且列舉的個數達地10來個,我們不可能在模板頁面(jsp/ftl/html)等頁面進行多大10多項的if判斷,去一個一個的判斷值,假如以後隨著業務的增多,列舉個數越來越多