最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Objective-C關鍵字@property使用原理探究

 更新時間:2023年01月06日 09:27:36   作者:山海飛鳥  
這篇文章主要為大家介紹了Objective-C關鍵字@property使用原理探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

@property

@property是OC開發(fā)中常用到的關鍵字,今天這篇文章就為它做一個較為系統(tǒng)全面的總結

主要包含內容

接下來我會分別解析

存取器方法

一般訪問存取器方法只需要使用.propertyName即可,需要特別指定存取器方法時可通過getter=getterNamesetter=setterName,具體示例如下:

// 指定getter訪問名為isOpen

@property (nonatomic, assign, getter=isOpen) BOOL open;

// 指定setter方法名為setNickName:

@property (nonatomic, copy, setter=setNickName:) NSString *name;

讀寫權限

  • readwrite:表示自動生成對應的 getter 和 setter 方法,即可讀可寫權限, readwrite是編譯器的默認選項。
  • readonly:表示只生成 getter ,不需要生成 setter ,即只可讀,不可以修改。

內存管理

  • strong:指定與目標對象存在強(擁有)的關系,修飾對象的引用計數會+1,通常用來修飾對象類型,可變集合及可變字符串類型。當對象引用計數為0,即不被任何對象持有,對象就會從內存中釋放
  • assign:不改變修飾對象的引用計數,通常用來修飾基本數據類型(NSInteger,NSNumberCGRect,CGFloat等),也是默認屬性。需要特別注意的一點是當修飾的對象的引用計數為0對象被銷毀的時候,對象指針不會自動清空成為野指針,后續(xù)再次訪問會產生野指針錯誤:EXC_BAD_ACCESS
  • copy:對象會在內存中拷貝一個副本,副本引用計數為1。一般用于不可變對象的集合類型,這是為了保證進行copy操作的時候生成的都是不可變類型。 copy分深拷貝與淺拷貝,對可變與不可變對象進行copy操作結果如下:
源對象類型拷貝方式目標對象類型拷貝類型(深|淺)
mutable對象copy不可變深拷貝
mutable對象mutableCopy可變深拷貝
immutable對象copy不可變淺拷貝
immutable對象mutableCopy可變深拷貝

可以總結以下兩點:

對mutable對象的拷貝都是深拷貝

所有對象的copy結果都是不可變

weak:弱引用關系,修飾對象的引用計數不會增加,當修飾對象被銷毀的時候,對象指針會自動置為 nil,主要可以用于避免循環(huán)引用;weak 只能用來修飾對象類型,且是在 ARC 下新引入的修飾詞,只能修飾對象,MRC 下相當于使用 assign。

數據結構

struct SideTable {
    spinlock_t slock;// 用于給原子性操作加鎖
    RefcountMap refcnts;// 引用計數hash表
    weak_table_t weak_table;// weak對象指針hash表
}
/**
* The global weak references table. Stores object ids as keys,
* and weak_entry_t structs as their values.
*/
struct weak_table_t {
    weak_entry_t *weak_entries;// 存儲 weak 對象信息的 hash 數組
    size_t    num_entries;// 數組中元素的個數,數組初始化的時候默認4個,占用達到3/4會翻倍擴容
    uintptr_t mask;// 計數輔助量
    uintptr_t max_hash_displacement;// hash 元素最大偏移值
};

清除weak

對象dealloc的時候,會調用weak_clear_no_lock函數將指向該對象的弱引用指針置為nil,具體實現如下

// objc-weak.mm
/** 
 * Called by dealloc; nils out all weak pointers that point to the 
 * provided object so that they can no longer be used.
 * 
 * @param weak_table 
 * @param referent The object being deallocated. 
 */
void 
weak_clear_no_lock(weak_table_t *weak_table, id referent_id) 
{
    // 獲得 weak 指向的地址,即對象內存地址
    objc_object *referent = (objc_object *)referent_id; 
    // 找到管理 referent 的 entry 容器
    weak_entry_t *entry = weak_entry_for_referent(weak_table, referent); 
    // 如果 entry == nil,表示沒有弱引用需要置為 nil,直接返回
    if (entry == nil) { 
        /// XXX shouldn't happen, but does with mismatched CF/objc
        //printf("XXX no entry for clear deallocating %p\n", referent);
        return;
    }
    // zero out references
    weak_referrer_t *referrers;
    size_t count;
    if (entry->out_of_line()) { 
        // referrers 是一個數組,存儲所有指向 referent_id 的弱引用
        referrers = entry->referrers; 
        // 弱引用數組長度
        count = TABLE_SIZE(entry);    
    } 
    else {
        referrers = entry->inline_referrers;
        count = WEAK_INLINE_COUNT;
    }
    // 遍歷弱引用數組,將所有指向 referent_id 的弱引用全部置為 nil
    for (size_t i = 0; i < count; ++i) {
        objc_object **referrer = referrers[i];
        if (referrer) {
            if (*referrer == referent) {
                *referrer = nil;
            }
            else if (*referrer) {
                _objc_inform("__weak variable at %p holds %p instead of %p. "
                             "This is probably incorrect use of "
                             "objc_storeWeak() and objc_loadWeak(). "
                             "Break on objc_weak_error to debug.\n", 
                             referrer, (void*)*referrer, (void*)referent);
                objc_weak_error();
            }
        }
    }
    // 從 weak_table 中移除對應的弱引用的管理容器
    weak_entry_remove(weak_table, entry);
}

總結:

當一個對象被銷毀時,在dealloc方法內部經過一系列的函數調用棧,通過兩次哈希查找,第一次根據對象的地址找到它所在的Sidetable,第二次根據對象的地址在Sidetableweak_table中找到它的弱引用表。弱引用表中存儲的是對象的地址(作為key)和weak指針地址的數組(作為value)的映射。weak_clear_no_lock函數中遍歷弱引用數組,將指向對象的地址的weak變量全都置為nil

添加weak

一個被聲明為__weak的指針,在經過編譯之后。通過objc_initWeak函數初始化附有__weak修飾符的變量,在變量作用域結束時通過objc_destroyWeak函數銷毀該變量。

id obj = [[NSObject alloc] init];
id __weak obj1 = obj;
/*----- 編譯 -----*/
id obj1;
objc_initWeak(&amp;obj1,obj);
objc_destroyWeak(&amp;obj1);

objc_initWeak函數調用棧如下:

// NSObject.mm
1. objc_initWeak
2. storeWeak
// objc-weak.mm
3. weak_register_no_lock
4. weak_unregister_no_lock

總結:

一個被標記為__weak的指針,在經過編譯之后會調用objc_initWeak函數,objc_initWeak函數中初始化weak變量后調用storeWeak。添加weak的過程如下:
經過一系列的函數調用棧,最終在weak_register_no_lock()函數當中,進行弱引用變量的添加,具體添加的位置是通過哈希算法來查找的。如果對應位置已經存在當前對象的弱引用表(數組),那就把弱引用變量添加進去;如果不存在的話,就創(chuàng)建一個弱引用表,然后將弱引用變量添加進去。(weak相關實現較為復雜后續(xù)的文章會做專門解析)

retain:MRC下使用,ARC下使用strong,用來修飾對象類型,強引用對象,其修飾對象的引用計數會 +1,不會對對象分配新的內存空間。

unsafe_unretained:同weak類似,不會對對象的引用計數 +1,只能用來修飾對象類型,修飾的對象在被銷毀時,其指針不會自動清空,指向的仍然是已銷毀的對象,這時再調用該指針會產生野指針EXC_BAD_ACCESS錯誤。

原子性

atomic 原子性:系統(tǒng)會自動給生成的 getter/setter 方法進行加鎖操作; nonatomic 非原子性:系統(tǒng)不會給自動生成的 getter/setter 方法進行加鎖操作; 設置屬性函數 reallySetProperty(...) 的原子性非原子性實現如下:

if (!atomic) {
    oldValue = *slot;
    *slot = newValue;
} else {
    spinlock_t& slotlock = PropertyLocks[slot];
    slotlock.lock();
    oldValue = *slot;
    *slot = newValue;        
    slotlock.unlock();
}

獲取屬性函數 objc_getProperty(...) 的內部實現如下:

    if (offset == 0) {
        return object_getClass(self);
    }
    // Retain release world
    id *slot = (id*) ((char*)self + offset);
    if (!atomic) return *slot;
    // Atomic retain release world
    spinlock_t& slotlock = PropertyLocks[slot];
    slotlock.lock();
    id value = objc_retain(*slot);
    slotlock.unlock();
    // for performance, we (safely) issue the autorelease OUTSIDE of the spinlock.
    return objc_autoreleaseReturnValue(value);

總結

由上面代碼可見atomic只能對存取器方法加鎖,并不能保障多線程下對對象的其他操作安全。

以上就是Objective-C關鍵字@property使用原理探究的詳細內容,更多關于Objective-C關鍵字@property的資料請關注腳本之家其它相關文章!

相關文章

  • IOS實現簽到特效(散花效果)的實例代碼

    IOS實現簽到特效(散花效果)的實例代碼

    這篇文章主要介紹了IOS實現簽到特效(散花效果)的實例代碼,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-05-05
  • iOS CoreData 增刪改查詳解

    iOS CoreData 增刪改查詳解

    這篇文章主要為大家詳細介紹了iOS CoreData 增刪改查的相關資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-09-09
  • ios實現文件對比的方法

    ios實現文件對比的方法

    這篇文章主要介紹了ios實現文件對比的方法,主要是用到了filemanager,有需要的小伙伴可以參考下。
    2015-05-05
  • 替代pod update速度慢的lg_pod_plugin安裝使用詳解

    替代pod update速度慢的lg_pod_plugin安裝使用詳解

    這篇文章主要介紹了替代pod update速度慢lg_pod_plugin安裝使用方式詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-09-09
  • 實例解析iOS應用多線程開發(fā)中NSthread類的用法

    實例解析iOS應用多線程開發(fā)中NSthread類的用法

    這篇文章主要介紹了iOS應用多線程開發(fā)中NSthread類的用法,代碼基于傳統(tǒng)的Objective-C,NSthread類需要的朋友可以參考下
    2016-02-02
  • iOS實現點擊狀態(tài)欄自動回到頂部效果詳解

    iOS實現點擊狀態(tài)欄自動回到頂部效果詳解

    在IOS開發(fā)過程中,經常會有這種需求,需要通過點擊狀態(tài)欄返回到頂部,給用戶更好的體驗效果,下面這篇文章給大家詳細介紹了實現過程,有需要的可以參考借鑒。
    2016-09-09
  • IOS 下獲取 rootviewcontroller 的版本不同的問題解決辦法

    IOS 下獲取 rootviewcontroller 的版本不同的問題解決辦法

    這篇文章主要介紹了IOS 下獲取 rootviewcontroller 的版本不同的問題解決辦法的相關資料,希望通過本文能幫助到大家,讓大家遇到這種問題可以解決,需要的朋友可以參考下
    2017-10-10
  • iOS左右滑動標簽頁導航的設計

    iOS左右滑動標簽頁導航的設計

    這篇文章主要為大家詳細介紹了iOS左右滑動標簽頁導航的設計思路,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-06-06
  • iOS中Label實現顯示不同顏色與字體的方法

    iOS中Label實現顯示不同顏色與字體的方法

    這篇文章主要給大家介紹了關于在iOS中Label實現顯示不同顏色與字體的相關資料,文中分別介紹了利用range或者文字兩種實現的方法,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-11-11
  • 舉例詳解iOS開發(fā)過程中的沙盒機制與文件

    舉例詳解iOS開發(fā)過程中的沙盒機制與文件

    這篇文章主要介紹了舉例詳解iOS開發(fā)過程中的沙盒機制與文件,示例代碼為傳統(tǒng)的Obejective-C,需要的朋友可以參考下
    2015-09-09

最新評論

韶关市| 大宁县| 丰县| 龙陵县| 花莲市| 阿城市| 河南省| 梅河口市| 南岸区| 无极县| 富民县| 樟树市| 嘉义县| 高碑店市| 景泰县| 白朗县| 米易县| 诏安县| 桃园县| 保山市| 砀山县| 博白县| 黔西| 惠安县| 建水县| 定南县| 奉节县| 双鸭山市| 海南省| 五家渠市| 通山县| 沾益县| 迭部县| 淮南市| 巴南区| 兴仁县| 罗城| 孟州市| 麻城市| 斗六市| 且末县|