1. ios 怎麼用runtime來動態傳值修改屬性
首先定義一個類
#import@interface Person : NSObject
@property (assign, nonatomic) NSInteger age;
-(void)run;
@end
#import "Person.h"
@implementation Person
-(void)run{
NSLog(@"%s",__func__);
}
@end
定義分類
#import "Person.h"
@interface Person (Extention)
@property (, nonatomic) NSString *name;
-(void)saySex;
@end
#import "Person+Extention.h"
#import <objc/runtime.h>
@implementation Person (Extention)
//定義常量 必須是c語言字元串
static char *PersonNameKey = "PersonNameKey";
-(void)setName:(NSString *)name{
/*
OBJC_ASSOCIATION_ASSIGN; //assign策略
OBJC_ASSOCIATION_COPY_NONATOMIC; //策略
OBJC_ASSOCIATION_RETAIN_NONATOMIC; // retain策略
OBJC_ASSOCIATION_RETAIN;
OBJC_ASSOCIATION_COPY;
*/
/*
* id object 給哪個對象的屬性賦值
const void *key 屬性對應的key
id value 設置屬性值為value
objc_AssociationPolicy policy 使用的策略,是一個枚舉值,和,retain,assign是一樣的,手機開發一般都選擇NONATOMIC
objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);
*/
objc_setAssociatedObject(self, PersonNameKey, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
-(NSString *)name{
return objc_getAssociatedObject(self, PersonNameKey);
}
-(void)saySex{
NSLog(@"%s----%@",__func__,self);
}
@end
總結:在分類中@property不會生成_變數,也不會實現getter和setter方法,我們可以手動實現如下
-(NSString *)name{
return @"name";
}
-(void)setName:(NSString *)name{
}
但是這樣是沒什麼意義的,而且分類中不允許定義變數,所以只能用runtime類實現
2. 理解ios的runtime機制有什麼用
一.RunLoop:
Runloop是事件接收和分發機制的一個實現。
Runloop提供了一種非同步執行代碼的機制,不能並行執行任務。
在主隊列中,Main RunLoop直接配合任務的執行,負責處理UI事件、定時器以及其他內核相關事件。
(1).RunLoop的主要目的:
保證程序執行的線程不會被系統終止。
(2).什麼時候使用Runloop ?
當需要和該線程進行交互的時候才會使用Runloop.
每一個線程都有其對應的RunLoop,但是默認非主線程的RunLoop是沒有運行的,需要為RunLoop添加至少一個事件源,然後去run它。
一般情況下我們是沒有必要去啟用線程的RunLoop的,除非你在一個單獨的線程中需要長久的檢測某個事件。
主線程默認有Runloop。當自己啟動一個線程,如果只是用於處理單一的事件,則該線程在執行完之後就退出了。所以當我們需要讓該線程監聽某項事務
時,就得讓線程一直不退出,runloop就是這么一個循環,沒有事件的時候,一直卡著,有事件來臨了,執行其對應的函數。
RunLoop,正如其名所示,是線程進入和被線程用來相應事件以及調用事件處理函數的地方.需要在代碼中使用控制語句實現RunLoop的循環,也就是說,需要代碼提供while或者for循環來驅動RunLoop.
在這個循環中,使用一個runLoop對象[NSRunloop currentRunloop]執行接收消息,調用對應的處理函數.
Runloop接收兩種源事件:input sources和timer sources。
input sources 傳遞非同步事件,通常是來自其他線程和不同的程序中的消息;
timer sources(定時器) 傳遞同步事件(重復執行或者在特定時間上觸發)。
除了處理input sources,Runloop
也會產生一些關於本身行為的notificaiton。注冊成為Runloop的observer,可以接收到這些notification,做一些額外
的處理。(使用CoreFoundation來成為runloop的observer)。
Runloop工作的特點:
1>當有時間發生時,Runloop會根據具體的事件類型通知應用程序作出相應;
2>當沒有事件發生時,Runloop會進入休眠狀態,從而達到省電的目的;
3>當事件再次發生時,Runloop會被重新喚醒,處理事件.
提示:一般在開發中很少會主動創建Runloop,而通常會把事件添加到Runloop中.
二.Runtime:
RunTime簡稱運行時。就是系統在運行的時候的一些機制,其中最主要的是消息機制。對於C語言,函數的調用在編譯的時候會決定調用哪個函數(
C語言的函數調用請看這里
)。編譯完成之後直接順序執行,無任何二義性。OC的函數調用成為消息發送。屬於動態調用過程。在編譯的時候並不能決定真正調用哪個函數(事實證明,在編
譯階段,OC可以調用任何函數,即使這個函數並未實現,只要申明過就不會報錯。而C語言在編譯階段就會報錯)。只有在真正運行的時候才會根據函數的名稱找
到對應的函數來調用。
那OC是怎麼實現動態調用的呢?下面我們來看看OC通過發送消息來達到動態調用的秘密。假如在OC中寫了這樣的一個代碼:
[objc] view plain?
<span style="font-size:18px;">[obj makeText];</span>
其中obj是一個對象,makeText是一個函數名稱。對於這樣一個簡單的調用。在編譯時RunTime會將上述代碼轉化成
[objc] view plain?
objc_msgSend(obj,@selector(makeText));
首先我們來看看obj這個對象,iOS中的obj都繼承於NSObject。
[objc] view plain?
@interface NSObject <nsobject> {
Class isa OBJC_ISA_AVAILABILITY;
}</nsobject>
在NSObjcet中存在一個Class的isa指針。然後我們看看Class:
[objc] view plain?
typedef struct objc_class *Class;
struct objc_class {
Class isa; // 指向metaclass
Class super_class ; // 指向其父類
const charchar *name ; // 類名
long version ; // 類的版本信息,初始化默認為0,可以通過runtime函數class_setVersion和class_getVersion進行修改、讀取
long info; // 一些標識信息,如CLS_CLASS (0x1L) 表示該類為普通 class ,其中包含對象方法和成員變數;CLS_META (0x2L) 表示該類為 metaclass,其中包含類方法;
long instance_size ; // 該類的實例變數大小(包括從父類繼承下來的實例變數);
struct objc_ivar_list *ivars; // 用於存儲每個成員變數的地址
struct objc_method_list **methodLists ; // 與 info 的一些標志位有關,如CLS_CLASS (0x1L),則存儲對象方法,如CLS_META (0x2L),則存儲類方法;
struct objc_cache *cache; // 指向最近使用的方法的指針,用於提升效率;
struct objc_protocol_list *protocols; // 存儲該類遵守的協議
}
我們可以看到,對於一個Class類中,存在很多東西,下面我來一一解釋一下:
Class
isa:指向metaclass,也就是靜態的Class。一般一個Obj對象中的isa會指向普通的Class,這個Class中存儲普通成員變數和對
象方法(「-」開頭的方法),普通Class中的isa指針指向靜態Class,靜態Class中存儲static類型成員變數和類方法(「+」開頭的方
法)。
Class super_class:指向父類,如果這個類是根類,則為NULL。
下面一張圖片很好的描述了類和對象的繼承關系:
注意:所有metaclass中isa指針都指向跟metaclass。而跟metaclass則指向自身。
Root metaclass是通過繼承Root class產生的。與root class結構體成員一致,也就是前面提到的結構。不同的是Root
metaclass的isa指針指向自身。
3. runtime實現的機制是什麼,有哪些用法,一般用於幹嘛
runtime庫裡麵包含了跟類、成員變數、方法相關的API,比如獲取類裡面的所有成員變數,為類動態添加成員變數,動態改變類的方法實現,為類動態添加新的方法等 需要導入<objc/message.h><objc/runtime.h>1.是什麼
1> runtime是一套比較底層的純C語言API, 屬於1個C語言庫, 包含了很多底層的C語言API
2> 平時編寫的OC代碼, 在程序運行過程中, 其實最終都是轉成了runtime的C語言代碼, runtime算是OC的幕後工作者
3> 舉例:
OC :
[[MJPerson alloc] init]runtime :
objc_msgSend(objc_msgSend("MJPerson" , "alloc"), "init")2.用過么? 怎麼用?
1> runtime是屬於OC的底層, 可以進行一些非常底層的操作(用OC是無法現實的, 不好實現)
* 在程序運行過程中, 動態創建一個類(比如KVO的底層實現)
* 在程序運行過程中, 動態地為某個類添加屬性方法, 修改屬性值方法
* 遍歷一個類的所有成員變數(屬性)所有方法3.相關的頭文件和函數
1> 頭文件
* <objc/runtime.h>
* <objc/message.h>2> 相關應用
* NSCoding(歸檔和解檔, 利用runtime遍歷模型對象的所有屬性)
* 字典 --> 模型 (利用runtime遍歷模型對象的所有屬性, 根據屬性名從字典中取出對應的值, 設置到模型的屬性上)
* KVO(利用runtime動態產生一個類)
* 用於封裝框架(想怎麼改就怎麼改)3> 相關函數
* objc_msgSend : 給對象發送消息
* class_MethodList : 遍歷某個類所有的方法
* class_IvarList : 遍歷某個類所有的成員變數
* class_.....
4. 運行(run)模式工作原理
工作原理是 Objective-C是一門動態語言,它會將一些工作放在代碼運行時才處理而並非編譯時。
Runtime又叫運行時,是一套底層的C語言API,其為iOS內部的核心之一,我們平時編寫的OC代碼,底層都是基於它來實現的。
5. iOS之runtime詳解api(一)
runtime 在iOS中是「運行時」的含義,是一套用c語言寫的api,很多人會用但是也僅僅用過最最常用的幾個函數,這次,我將詳細的帶著大家探索下 runtime 的API,這一章就說下 <objc/runtime.h> 這個文件里的 API ,並且我會把不適用於 ARC 和不支持64位的API剔除掉。
首先,我們先看一個簡單的函數:
這個函數是通過傳入 Class 類型的 cls 來得到 Class 的名字。那我們測試下這個函數:
其中 [Person class] OC中獲得 Class 的方法,當然,你也可以用 runtime 裡面的 objc_getClass 等函數,後面我也會講到。
運行結果:
我們可以看到列印出來的結果就是類的名字。
上面既然用到了 [Person class] ,那我們就看下在 runtime 中 [Person class] 的替代函數,都是通過名字來獲得 Class
那這三個有什麼區別,從結論上講, objc_getClass 和 objc_lookUpClass 的效果是一致的,在最新的源碼裡面,這兩個方法調用的底層也是一致的,當你要找的類不存在的話,就返回nil,而 objc_getRequiredClass 里你要找的類不存在的話,就會崩潰。下面我們來測試下,我們創建一個 Person 類。
運行結果:
最後也確實崩潰了,所以大家使用 objc_getRequiredClass 這個函數時候要慎重小心。
除了用名字獲得類對象以外,還可以用實例對象來獲取:
我們測試下:
運行結果:
完全沒問題。
Class 不僅可以代表類對象,也可以代表元類對象,下面這個函數就是通過名字獲取元類對象。
如果你讀過源碼的話,你就會清楚元類對象儲存的是類方法,類對象儲存的是實例方法,在後面講到Method相關的API的時候,我們在具體講他們之間的區別。
講到元類對象,我們還要關注下這個函數,
這個函數是用來判斷是否是元類對象。
運行結果:
我們可以看到 objc_getMetaClass 生成才是元類對象, objc_getClass 生成的只是類對象。
那麼有沒有函數區分類(元類)對象和實例對象呢?當然有:
這個方法只要是類對象或者元類對象都會返回YES:
運行結果:
當然也可以獲得父類對象。
我們新建一個繼承 Person 的類 Student ,然後我們通過 Student 類來獲得 Person 類。
運行結果:
Student 的父類確實是 Person 。
我們知道OC裡面可以強轉類型,當然, runtime 裡面也有相關方法
這個方法的意思是給一個實例對象設置新的類,返回舊的類
運行結果:
我們可以看出開始的時候 student 的類是 Student ,用了 object_setClass 後就是 Person 類了。
runtime 的動態性還可以動態新增類,下面四個函數分別表示為一個類分配內存,注冊一個類,復制一個類,銷毀一個類
創建一個新類, superclass 是新類所繼承的類,如果為 nil , superclass 就默認為根類,也就是 NSObject , extraBytes 是在類和元類對象的末尾為索引ivars分配的位元組數。這一般是0, name 是新類的名字。
注冊類,如果這個類 objc_allocateClassPair 好了,就必須 objc_registerClassPair 才能使用。
這個方法在系統KVO的底層用過,系統不推薦我們自己用。
objc_disposeClassPair 只能銷毀通過 objc_allocateClassPair 創建的類。
我們寫個demo來測試這些方法, objc_plicateClass 官方不建議使用,那麼我們就不測試這函數。
運行結果:
我們可以知道如果僅僅只是 objc_allocateClassPair 的話,你是找不到這個類的,必須再 objc_registerClassPair 才可以找到, objc_disposeClassPair 則是把類銷毀掉,所以再實際開發中,如果我們不再使用自建類的時候,就要及時銷毀,節省內存。
下面兩個函數是關於整個工程的類列表的函數:
這個函數是獲得所有注冊類的列表,我們試用下:
運行結果:
我們看到注冊的類有15765個。
objc_getClassList 也是獲取注冊類的方法.
第一個參數 buffer 已分配好內存空間的數組指針, bufferCount 是數組的個數,如果 bufferCount 的數量小於實際的數組數量,那麼 buffer 返回的是所有數組集合的任意一個子類。如果 buffer 為NULL,那麼 bufferCount 為0。無論那種情況,返回結果都是當前注冊類的總數。
運行結果:
返回類實例的大小。
運行結果
一個沒有變數或屬性的繼承於NSObject的類佔有8個位元組。
還有個方法是:
這是一個創建實例的方法, cls 是要創建的類, extraBytes 是額外的位元組內存,用來存儲類定義中的實例變數之外的其他實例變數。在源碼中 alloc 方法底層就是用的這個函數。那麼,我們用這個函數來初始化 Person 類:
運行結果:
確實能夠成功創建出來。
最後剩下兩個方法:
這兩個方法都和 version 有關,這個version在實際中我也沒發現用處,可能是在改變類的變數或者方法時給定一個標識.
運行結果
下面我們將使用runtime裡面最最常用的api,也就是給分類綁定對象,這里,我們先了解下,一個枚舉:
objc_AssociationPolicy 是一個枚舉,裡面的枚舉值分別代表要添加的屬性的修飾類型。
OBJC_ASSOCIATION_ASSIGN 相當於 weak
OBJC_ASSOCIATION_RETAIN_NONATOMIC 相當於 strong 和 nonatomic
OBJC_ASSOCIATION_COPY_NONATOMIC 相當於 和 nonatomic
OBJC_ASSOCIATION_RETAIN 相當於 strong 和 atomic
OBJC_ASSOCIATION_COPY 相當於 和 atomic
關於分類的runtime函數,主要有下面3個:
含義分別為設置關聯對象,獲得關聯對象,刪除關聯對象。
我們知道如果在分類的 .h 文件設置屬性並沒有用,調用的時候會發生閃退,這是因為系統並沒有自動為屬性生成 Set 和 Get 方法,所以,我們用上面三個方法來手動關聯對象。
我們創建一個 Person 的分類 Person+Actor.h ,在.h文件里新建一個新屬性 @property(nonatomic, assign)float actingSkill 而不做其他任何處理,這時候, .m 文件就會有警告。
這時候就綁定好了。
在 ViewController 裡面去使用下這個屬性
運行結果:
說明set和get方法都成功了。
那麼還有一個 objc_removeAssociatedObjects 方法還沒用,這個方法是解除綁定,為了測試這個效果,我們在ViewController裡面 touchesBegan 裡面去調用這個方法。
運行結果:
之前綁定的結果被移除了。
今天我們這一篇就講到這, runtime 還有很多其他的用法我們下一篇見。
對了,這個是 demo ,喜歡的可以點個星。
6. c語言編程時當出現runtime erro時要怎麼辦一般是什麼原因!
Runtime是運行時的意思,Runtime
Error就是運行時錯誤,就是在運行期間出現的錯誤。
webopedia
關於
運行時錯誤的定義:
運行時錯誤是程序執行期間發生的錯誤,它不同於編譯期間發生的錯誤.運行時錯誤可能是程序中的毛病引起的,也可能程序並無錯誤,例如機器存儲器不夠引起
所以:很有可能是你對內存的操作出現了問題。多檢查指針方面的代碼,看是不是有問題
7. C語言報錯出現runtime error如何處理
RuntimeError常見出錯的原因可能有以下幾種:
1、數組開得太小了,導致訪問到了不該訪問的內存區域
2、發生除零錯誤
3、大數組定義在函數內,導致程序棧區耗盡
4、指針用錯了,導致訪問到不該訪問的內存區域
5、還有可能是程序拋出了未接收的異常
轉自CSDN網頁鏈接
8. C語言Runtime Error的原因是什麼
runtime error (運行時錯誤)就是程序運行到一半,程序就崩潰了。
原因有很多,比如說:①除以零②數組越界:int a[3]; a[10000000]=10;③指針越界:int * p; p=(int *)malloc(5 * sizeof(int)); *(p+1000000)=10;④使用已經釋放的空間:int * p; p=(int *)malloc(5 * sizeof(int));free(p); *p=10;⑤數組開得太大,超出了棧的范圍,造成棧溢出:int a[100000000];
根據經驗,大多數情況是因為程序員對內存的理解不透徹導致錯誤應用引起的~
9. iOS Runtime理解
runtime
概述: runtime又叫運行時,是一套底層C語言API,是iOS系統的核心之一。開發者在編碼過程中,可以給任意一個對象發送消息,在編譯階段只是確定了要向接受著發送這條消息,而接受者如何響應和處理這條消息,就要看運行時來決定了
C語言中,在編譯器就確定要調用哪個函數,而OC的函數,屬於動態調用過程,在編譯器並不能真正決定調用哪個函數,只有在真正的運行時才會根據函數的名稱找到對應的函數來調用。OC是一個動態語言,這意味著它不僅要一個編譯器,也需要一個運行時系統來動態創建類和對象、進行消息傳遞和發送
1.消息轉發
Runtime的特性主要是消息傳遞,如果消息在對象中找不到,就進行轉發。Objective-C是一個動態語言,這意味著它不僅需要一個編譯器,也需要一個運行時系統來動態創建類和對象、進行消息傳遞和轉發。Runtime的核心是消息傳遞。
(1)消息傳遞的過程
一個對象的方法[obj test],編譯器轉成消息發送objc_msgSend(obj,test),Runtime執行的流程是這樣的
a.首先通過obj的isa指針找到它的class
b.在class的method list找test
c.如果class中沒找到test,繼續往它的superclass中找
d.一旦找到test這個函數,就去執行它的IMP
由於效率問題,每個消息都遍歷一次objc_method_list並不合理,所以需要把經常被調用的函數緩存下來,去提高函數查詢的效率。這也就是objc_class中另一個重要的成員objc_cache做的事情。找到test之後,將test的method_name作為key,method_imp作為value。當再次收到test消息的時候,可以直接在cache里找。
類對象(objc_class)
Objective-C類是由Class類型來表示的,它實際上是一個指向objc_class結構體的指針。struct objc_class結構體裡面定義了很多變數。結構體里保存了指向父類的指針、類的名字(name)、版本、實例變數列表(ivars)、方法列表(methodLists)、緩存(cache)、遵守的協議列表(protocols),由此可見,類對象就是一個結構體struct objc_class,這個結構體存放的數據就是元數據
理解Runtime就是理解iOS在運行時他的數據存儲以及他的類、實例、類對象、元類她們之間的關系和作用。
(2)消息轉發機制
歸根到底,Objective-C中所有的方法調用本質就是向對象發送消息
1.類中創建方法-(void)test
2.iOS系統為這個方法創建一個編號,SEL(test)並添加到方法列表裡面
3.當調用這個方法的時候系統去方法列表裡查找這個方法,找到了就執行
所以,調用一個方法就會進行一次發送消息也就是在這個類的方法列表裡找,如果在該類中找不到就到該類的父類里找,如果父類還找不到就一直搜索到繼承樹的根部,如果找不到或者消息轉發不成功那就會報unrecognized selector錯。
1.動態方法解析
Objective-C運行時會調用+resolveInstanceMethod:或者 +resolveClassMethod:讓你有機會提供一個函數實現,如果你添加了函數並且返回YES,那麼運行時就會重新啟動一次消息發送的過程。如下圖:
雖然沒有foo:的實現函數,但是通過class_addMethod()動態添加了fooMethod函數,並執行了這個函數並且列印成功。如果reslove返回NO運行時就會移到下一步:forwardingTargetSelector
2.直接消息轉發
如果目標對象實現了forwardingTargetSelector,Runtime這時就會調用這個方法,給你把這個消息轉發給其他對象的機會
從圖中可以看出我們通過forwardingTargetForSelector方法將當前類的方法轉給Father類實現了,列印成功。
3.完整消息轉發
如果在上一步還不能處理未知消息,那唯一能做的就是啟動消息轉發機制。首先它會發送methodSignatureForSelector消息獲得函數的參數和返回值類型。如果methodSignatureForSelector返回nil,Runtime則會發出doesNotRecognizeSelector。如果返回一個簽名函數,Runtime就會創建一個NSInvocation對象並發送forwardInvocation消息給目標對象。
Runtime的實際應用
1.使用Runtime交換方法
2.動態添加方法(目前不是很懂)
3.給分類添加屬性
4.消息轉發(熱更新)解決Bug(JSPatch)
10. 學習iOS開發C語言要學哪些基礎知識
C語言是一種計算機程序設計語言。它既有高級語言的特點,又具有匯編語言的特點。它可以作為系統設計語言, 編寫工作系統應用程序,也可以作為應用程序設計語言,編寫不依賴計算機硬體的應用程序。因此,它的應用范圍廣泛。 C語言在很多方面都可以用,不僅僅是在軟體開發上,各類科研都是需要用到C語言的。C語言是最受歡迎的語言之一。iOS開發網路全書—C語言網路
1.編程入門
首先介紹C語言的學習路線、環境搭建、iOS編程的行業前景、計算機的基本工作原理,為剛入門的初學者做鋪墊,有一個基本概念,方便以後的學習。
2.C語言的基本概念
對學習路線中的各個階段的是知識點有個簡單的了解,並用項目的形式展示出我們學習之後可以做的事情,後續劇情先知先覺,學時豁然開朗,輕松接收。
3.格式化輸入輸出與基本類型
介紹了最基本的輸入輸出、進制、整形、浮點型、字元型的數據及其轉換,用最簡單的方式編最簡單的C程序。
4.流程式控制制
介紹了流程的基本概念、分支語句、循環語句的概念、基本語法、與應用。程序如何判斷,判斷的條件,把我們解決問題的流程放進程序中表達的基本課程。
5.函數
詳細介紹了函數的基本概念,函數的組成,函數的用法。高效編程,一勞永逸,把簡單的功能模塊化,函數就是利器。