浅谈iOS之weak底层实现原理

iOS 内存管理浅谈 iOS 内存管理理解 阅读详情

前言

在iOS开发过程中,会经常使用到一个修饰词“weak”,使用场景大家都比较清晰,用于一些对象相互引用的时候,避免出现强强引用,对象不能被释放,出现内存泄露的问题。

weak 关键字的作用弱引用,所引用对象的计数器不会加一,并在引用对象被释放的时候自动被设置为 nil。

weak底层原理

1.weak编译解析

首先需要看一下weak编译之后具体出现什么样的变化,通过Clang的方法把weak编译成C++

int main(){
    NSObject *obj = [[NSObject alloc] init];
    id __weak obj1 = obj;
}

编译之后的weak,通过objc_ownership(weak)实现weak方法,objc_ownership字面意思是:获得对象的所有权,是对对象weak的初始化的一个操作。

在使用clang编译过程中会报错误,使用下方的方法编码编译出现error
clang -rewrite-objc -fobjc-arc -stdlib=libc++ -mmacosx-version-min=10.7 -fobjc-runtime=macosx-10.7 -Wno-deprecated-declarations main.m

int main(){
    NSObject *obj = ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc")), sel_registerName("init"));
    id __attribute__((objc_ownership(weak))) obj1 = obj;
}
2.weak的实现原理

第一、通过weak编译解析,可以看出来weak通过runtime初始化的并维护的;
第二、weak和strong都是Object-C的修饰词,而strong是通过runtime维护的一个自动计数表结构。
综上:weak是有Runtime维护的weak表。

在runtime源码中,可以找到’objc-weak.h’和‘objc-weak.mm’文件,并且在objc-weak.h文件中关于定义weak表的结构体以及相关的方法。

2.1.weak表

weak_table_t是一个全局weak 引用的表,使用不定类型对象的地址作为 key,用 weak_entry_t 类型结构体对象作为 value 。其中的 weak_entries 成员

/**
 * 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指针   weak_entries的对象
    size_t    num_entries;              // weak对象的存储空间
    uintptr_t mask;                      //参与判断引用计数辅助量
    uintptr_t max_hash_displacement;    //hash key 最大偏移值
};

weak全局表中的存储weak定义的对象的表结构weak_entry_t,weak_entry_t是存储在弱引用表中的一个内部结构体,它负责维护和存储指向一个对象的所有弱引用hash表。其定义如下:

typedef objc_object ** weak_referrer_t;
struct weak_entry_t {
    DisguisedPtr<objc_object> referent;  //范型
    union {
        struct {
            weak_referrer_t *referrers;
            uintptr_t        out_of_line : 1;
            uintptr_t        num_refs : PTR_MINUS_1;
            uintptr_t        mask;
            uintptr_t        max_hash_displacement;
        };
        struct {
            // out_of_line=0 is LSB of one of these (don't care which)
            weak_referrer_t  inline_referrers[WEAK_INLINE_COUNT];
        };
    }
}

在 weak_entry_t 的结构中,DisguisedPtr referent 是对泛型对象的指针做了一个封装,通过这个泛型类来解决内存泄漏的问题。从注释中写 out_of_line 成员为最低有效位,当其为0的时候, weak_referrer_t 成员将扩展为多行静态 hash table。其实其中的 weak_referrer_t 是二维 objc_object 的别名,通过一个二维指针地址偏移,用下标作为 hash 的 key,做成了一个弱引用散列。

out_of_line:最低有效位,也是标志位。当标志位 0 时,增加引用表指针纬度。
num_refs:引用数值。这里记录弱引用表中引用有效数字,因为弱引用表使用的是静态 hash 结构,所以需要使用变量来记录数目。
mask:计数辅助量。
max_hash_displacement:hash 元素上限阀值。
其实 out_of_line 的值通常情况下是等于零的,所以弱引用表总是一个 objc_objective 指针二维数组。一维 objc_objective 指针可构成一张弱引用散列表,通过第三纬度实现了多张散列表,并且表数量为 WEAK_INLINE_COUNT 。

objc_object是weak_entry_t表中weak弱引用对象的范型对象的结构体结构。

struct objc_object {
private:
    isa_t isa;

public:

    // ISA() assumes this is NOT a tagged pointer object
    Class ISA();

    // getIsa() allows this to be a tagged pointer object
    Class getIsa();

    // initIsa() should be used to init the isa of new objects only.
    // If this object already has an isa, use changeIsa() for correctness.
    // initInstanceIsa(): objects with no custom RR/AWZ
    // initClassIsa(): class objects
    // initProtocolIsa(): protocol objects
    // initIsa(): other objects
    void initIsa(Class cls /*indexed=false*/);
    void initClassIsa(Class cls /*indexed=maybe*/);
    void initProtocolIsa(Class cls /*indexed=maybe*/);
    void initInstanceIsa(Class cls, bool hasCxxDtor);

    // changeIsa() should be used to change the isa of existing objects.
    // If this is a new object, use initIsa() for performance.
    Class changeIsa(Class newCls);

    bool hasIndexedIsa();
    bool isTaggedPointer();
    bool isClass();

    // object may have associated objects?
    bool hasAssociatedObjects();
    void setHasAssociatedObjects();

    // object may be weakly referenced?
    bool isWeaklyReferenced();
    void setWeaklyReferenced_nolock();

    // object may have -.cxx_destruct implementation?
    bool hasCxxDtor();

    // Optimized calls to retain/release methods
    id retain();
    void release();
    id autorelease();

    // Implementations of retain/release methods
    id rootRetain();
    bool rootRelease();
    id rootAutorelease();
    bool rootTryRetain();
    bool rootReleaseShouldDealloc();
    uintptr_t rootRetainCount();

    // Implementation of dealloc methods
    bool rootIsDeallocating();
    void clearDeallocating();
    void rootDealloc();

private:
    void initIsa(Class newCls, bool indexed, bool hasCxxDtor);

    // Slow paths for inline control
    id rootAutorelease2();
    bool overrelease_error();

#if SUPPORT_NONPOINTER_ISA
    // Unified retain count manipulation for nonpointer isa
    id rootRetain(bool tryRetain, bool handleOverflow);
    bool rootRelease(bool performDealloc, bool handleUnderflow);
    id rootRetain_overflow(bool tryRetain);
    bool rootRelease_underflow(bool performDealloc);

    void clearDeallocating_weak();

    // Side table retain count overflow for nonpointer isa
    void sidetable_lock();
    void sidetable_unlock();

    void sidetable_moveExtraRC_nolock(size_t extra_rc, bool isDeallocating, bool weaklyReferenced);
    bool sidetable_addExtraRC_nolock(size_t delta_rc);
    bool sidetable_subExtraRC_nolock(size_t delta_rc);
    size_t sidetable_getExtraRC_nolock();
#endif

    // Side-table-only retain count
    bool sidetable_isDeallocating();
    void sidetable_clearDeallocating();

    bool sidetable_isWeaklyReferenced();
    void sidetable_setWeaklyReferenced_nolock();

    id sidetable_retain();
    id sidetable_retain_slow(SideTable *table);

    bool sidetable_release(bool performDealloc = true);
    bool sidetable_release_slow(SideTable *table, bool performDealloc = true);

    bool sidetable_tryRetain();

    uintptr_t sidetable_retainCount();
#if !NDEBUG
    bool sidetable_present();
#endif
};

总之:
1.weak_table_t(weak 全局表):采用hash(哈希表)的方式把所有weak引用的对象,存储所有引用weak对象
2.weak_entry_t(weak_table_t表中hash表的value值,weak对象体):用于记录hash表中weak对象
3.objc_object(weak_entry_t对象中的范型对象,用于标记对象weak对象):用于标示weak引用的对象。

详细讲解weak存储对象结构,对接下来对weak操作使用可以更加清晰的理解weak的使用。

2.2.weak底层实现原理

在runtime源码中的NSObject.mm文件中找到了关于初始化和管理weak表的方法

  • 初始化weak表方法
//初始化weak表
/** 
 * Initialize a fresh weak pointer to some object location. 
 * It would be used for code like: 
 *
 * (The nil case) 
 * __weak id weakPtr;
 * (The non-nil case) 
 * NSObject *o = ...;
 * __weak id weakPtr = o;
 * 
 * @param addr Address of __weak ptr. 
 * @param val Object ptr. 
 */
id objc_initWeak(id *addr, id val)
{
    *addr = 0;
    if (!val) return nil;
    return objc_storeWeak(addr, val); // 存储weak对象
}
  • 存储weak对象的方法
/** 
 * This function stores a new value into a __weak variable. It would
 * be used anywhere a __weak variable is the target of an assignment.
 * 
 * @param location The address of the weak pointer itself
 * @param newObj The new object this weak ptr should now point to
 * 
 * @return \e newObj
 */
id
objc_storeWeak(id *location, id newObj)
{
    id oldObj;
    SideTable *oldTable;
    SideTable *newTable;
    spinlock_t *lock1;
#if SIDE_TABLE_STRIPE > 1
    spinlock_t *lock2;
#endif

    // Acquire locks for old and new values.
    // Order by lock address to prevent lock ordering problems. 
    // Retry if the old value changes underneath us.
 retry:
    oldObj = *location;
    
    oldTable = SideTable::tableForPointer(oldObj);
    newTable = SideTable::tableForPointer(newObj);
    
    lock1 = &newTable->slock;
#if SIDE_TABLE_STRIPE > 1
    lock2 = &oldTable->slock;
    if (lock1 > lock2) {
        spinlock_t *temp = lock1;
        lock1 = lock2;
        lock2 = temp;
    }
    if (lock1 != lock2) spinlock_lock(lock2);
#endif
    spinlock_lock(lock1);

    if (*location != oldObj) {
        spinlock_unlock(lock1);
#if SIDE_TABLE_STRIPE > 1
        if (lock1 != lock2) spinlock_unlock(lock2);
#endif
        goto retry;
    }

    weak_unregister_no_lock(&oldTable->weak_table, oldObj, location);
    newObj = weak_register_no_lock(&newTable->weak_table, newObj, location);
    // weak_register_no_lock returns nil if weak store should be rejected

    // Set is-weakly-referenced bit in refcount table.
    if (newObj  &&  !newObj->isTaggedPointer()) {
        newObj->setWeaklyReferenced_nolock();
    }

    // Do not set *location anywhere else. That would introduce a race.
    *location = newObj;
    
    spinlock_unlock(lock1);
#if SIDE_TABLE_STRIPE > 1
    if (lock1 != lock2) spinlock_unlock(lock2);
#endif

    return newObj;
}
  • 旧对象解除注册操作 weak_unregister_no_lock

该方法主要作用是将旧对象在 weak_table 中接触 weak 指针的对应绑定。根据函数名,称之为解除注册操作。从源码中,可以知道其功能就是从 weak_table 中接触 weak 指针的绑定。而其中的遍历查询,就是针对于 weak_entry 中的多张弱引用散列表。

  • 新对象添加注册操作 weak_register_no_lock

这一步与上一步相反,通过 weak_register_no_lock 函数把心的对象进行注册操作,完成与对应的弱引用表进行绑定操作。

  • 初始化弱引用对象流程一览
    弱引用的初始化,从上文的分析中可以看出,主要的操作部分就在弱引用表的取键、查询散列、创建弱引用表等操作,可以总结出如下的流程图:

111.png

SideTable 这个结构体,是对weak_table_t表的再次封装操作,避免对weak_table_t直接操作,SideTable使用更加方便。

class SideTable {
private:
    static uint8_t table_buf[SIDE_TABLE_STRIPE * SIDE_TABLE_SIZE];

public:
    spinlock_t slock;
    RefcountMap refcnts;
    weak_table_t weak_table;

    SideTable() : slock(SPINLOCK_INITIALIZER)
    {
        memset(&weak_table, 0, sizeof(weak_table));
    }
    
    ~SideTable() 
    {
        // never delete side_table in case other threads retain during exit
        assert(0);
    }

    static SideTable *tableForPointer(const void *p) 
    {
#     if SIDE_TABLE_STRIPE == 1
        return (SideTable *)table_buf;
#     else
        uintptr_t a = (uintptr_t)p;
        int index = ((a >> 4) ^ (a >> 9)) & (SIDE_TABLE_STRIPE - 1);
        return (SideTable *)&table_buf[index * SIDE_TABLE_SIZE];
#     endif
    }

    static void init() {
        // use placement new instead of static ctor to avoid dtor at exit
        for (int i = 0; i < SIDE_TABLE_STRIPE; i++) {
            new (&table_buf[i * SIDE_TABLE_SIZE]) SideTable;
        }
    }
};

总之根据以上对weak进行存储的过程可以通过下边的流程图详细的描述出来
333.png

3.weak释放为nil过程

weak被释放为nil,需要对对象整个释放过程了解,如下是对象释放的整体流程:
1、调用objc_release
2、因为对象的引用计数为0,所以执行dealloc
3、在dealloc中,调用了_objc_rootDealloc函数
4、在_objc_rootDealloc中,调用了object_dispose函数
5、调用objc_destructInstance
6、最后调用objc_clear_deallocating。

对象准备释放时,调用clearDeallocating函数。clearDeallocating函数首先根据对象地址获取所有weak指针地址的数组,然后遍历这个数组把其中的数据设为nil,最后把这个entry从weak表中删除,最后清理对象的记录。

在对象被释放的流程中,需要对objc_clear_deallocating方法进行深入的分析

void objc_clear_deallocating(id obj) 
{
    assert(obj);
    assert(!UseGC);
    if (obj->isTaggedPointer()) return;
    obj->clearDeallocating();
}

//执行 clearDeallocating方法
inline void objc_object::clearDeallocating()
{
    sidetable_clearDeallocating();
}
// 执行sidetable_clearDeallocating,找到weak表中的value值
void  objc_object::sidetable_clearDeallocating()
{
    SideTable *table = SideTable::tableForPointer(this);
    // clear any weak table items
    // clear extra retain count and deallocating bit
    // (fixme warn or abort if extra retain count == 0 ?)
    spinlock_lock(&table->slock);
    RefcountMap::iterator it = table->refcnts.find(this);
    if (it != table->refcnts.end()) {
        if (it->second & SIDE_TABLE_WEAKLY_REFERENCED) {
            weak_clear_no_lock(&table->weak_table, (id)this);
        }
        table->refcnts.erase(it);
    }
    spinlock_unlock(&table->slock);
}

对weak置nil的操作最终调用执行weak_clear_no_lock方法用于执行置nil的操作。执行方法如下:

/** 
 * 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) 
{
    objc_object *referent = (objc_object *)referent_id;

    weak_entry_t *entry = weak_entry_for_referent(weak_table, referent);
    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 = entry->referrers;
        count = TABLE_SIZE(entry);
    } 
    else {
        referrers = entry->inline_referrers;
        count = WEAK_INLINE_COUNT;
    }
    
    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_entry_remove(weak_table, entry);
}

objc_clear_deallocating该函数的动作如下:

1、从weak表中获取废弃对象的地址为键值的记录
2、将包含在记录中的所有附有 weak修饰符变量的地址,赋值为nil
3、将weak表中该记录删除
4、从引用计数表中删除废弃对象的地址为键值的记录

其实Weak表是一个hash(哈希)表,然后里面的key是指向对象的地址,Value是Weak指针的地址的数组。

###总结
weak是Runtime维护了一个hash(哈希)表,用于存储指向某个对象的所有weak指针。weak表其实是一个hash(哈希)表,Key是所指对象的地址,Value是weak指针的地址(这个地址的值是所指对象指针的地址)数组。

机器学习第五章之决策树模型 机器学习专题系列 阅读详情

相关推荐

ArcGIS学习记录—SHP文件转换为KML KMZ数据,并显示面要素相应的标注

使用相应软件操作获取KMZ数据得以下发到外业调查人员,使得矢量数据能够更显而易见,可视化,让外业人员的工作减轻许多。(过程步骤是借鉴于网络上的相关人士给的建议,根据这些建议自己做出来的步骤,可能有些粗略,有问题的话可以再进行探讨)...

qq_41046162的博客 5万+

iOS底层原理:weak的实现原理

作者丨夜幕降临耶链接:https://juejin.im/post/5e7a322f6fb9a07ca24f79bb来源:掘金在iOS开发过程中,会经常...

iOS_开发 721

在Qt中使用EtherCAT-SOEM的初始化中,状态机卡在PreOp->Save-Op过程中,出现State=0x12, Error=0x001e错误的解决办法

1.在调试EtherCAT软件过程中,一直出现配置从站进不了Save_op状态,通过下函数检查从站状态: //使用的从站编号为1 只有1个从站 ec_slave[1].state = EC_STATE_SAFE_OP; ec_writestate(1); //设置到安全模式 ec_statecheck(1, EC_STATE_SAFE_OP, EC_TIMEOUTSTATE * 4); printf("Slave %d State=0x%2.2x StatusCode=0x%4

zeal_for_rov的博客 6828

iOS底层weak的实现原理

weak是弱引用,所引用对象的计数器不会加一,并在引用对象被释放的时候自动被设置为nil。那么weak的原理是什么呢?weak表其实是一个hash(哈希)表 (字典也是hash表),Key是所指对象的地址,Value是weak指针的地址数组。通常用于解决循环引用问题。下面就分析一下weak的工作原理。 weak 实现原理的概括 Runtime维护了一个weak表,用于存储指向某个对象的所有we...

gcs的博客 3964

BOE CHPI协议解析:高速显示驱动的核心技术

本文深入解析了BOE CHPI协议,这是一种为高分辨率、高刷新率显示面板设计的时钟嵌入式高速点对点接口技术。文章详细阐述了其三层架构(物理层、链路层、协议层)、核心机制(如链路训练与BCC通道)以及如何通过高速串行差分传输解决大尺寸屏幕内部数据传输的带宽与干扰难题,是驱动8K、窄边框等高端显示应用的关键核心技术。

m9n0o的博客 544

智能体开发套件(ADK)介绍

city } ---") city_normalized = city . lower() . replace(" " , "") # 模拟天气数据库 mock_weather_db = {

lpfasd123的博客 1406

【iOS】—— 属性关键字及weak关键字底层原理

使用宏和常量所占用的内存差别不大,宏定义的是常量,常量都放在常量区,只会生成一份内存编译时刻:宏是预编译(编译之前处理),const是编译阶段。导致使用宏定义过多的话,随着工程越来越大,编译速度会越来越慢宏不做检查,不会报编译错误,只是替换,const会编译检查,会报编译错误。宏能定义一些函数,方法。const不能。1.通过计算对象地址的哈希值, 来从SideTables中获取对应的SideTable. 哈希值重复的对象的引用计数存储在同一个SideTable里.2.SideTable使用。

m0_62386635的博客 2148

ESP32-S3驱动OV3660摄像头原理图设计,已量产

本文重点拆四条主线:多来源输入电源如何收敛到 3V3,摄像头三路供电如何拆分,ESP32-S3 如何接住 DVP 数据流与外部存储,以及音频/补光/传感外围怎样挂到主控边上。至于最终图像帧率、算法策略和软件时序,当前原理图未体现。

不脱发的程序猿 981

【iOS】—— weak的基本原理

1、weak的原理在于底层维护了一张结构的hash表,key是所指对象的地址,value是weak指针的地址数组。2、weak关键字的作用是弱引用,所引用对象的计数器不会加1,并在引用对象被释放的时候自动被设置为nil。3、对象释放时,调用函数根据对象地址获取所有weak指针地址的数组,然后遍历这个数组把其中的数据设为nil,最后把这个entry从weak表中删除,最后清理对象的记录。4、文章中介绍了SideTable、、这样三个结构,它们之间的关系如下图所示。httpshttps。......

m0_55124878的博客 1715

Oracle EBS R12 主 / 辅助分类帐(主 / 辅助帐套)落地

本文提供了Oracle EBS R12主/辅助分类帐实施的全套文档模板,包含主帐套(法定帐套)和辅助帐套的完整配置清单、科目映射规则模板、4类典型调整分录示例(存货跌价、折旧差异、往来重分类、外币折算)以及税会/IFRS案例分录。重点阐述了主/辅助帐套的配置要点、SLA子分类帐关键配置、科目映射规则(一对一、多对一、重分类等类型)以及调整分录的自动生成逻辑。文档可直接用于项目实施,包含总体架构图、科目映射矩阵表、会计规则集配置等交付物,并附有Excel版模板便于直接使用。适用于需要实现多准则并行记账、税务调

金牌架构师 386

如何使用 ABAP 代码调度一个 ABAP 程序,让其以后台作业的方式运行

笔者之前的教程,介绍了如何使用 SM36 一系列事务码,将一个 ABAP 程序,调度成以后台作业方式运行的详细步骤。 38. 如何让 ABAP 报表在后台作业的模式下运行 大家如果照着上述文章的步骤走一遍,会发现这些手动执行的步骤还是有些繁琐的。 有没有可能让这一切都自动化起来,即通过 ABAP 代码去完成呢?当然可以。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1943

「iOS」————weak底层原理

本文详细介绍了iOS中weak关键字的实现原理。weak是一种弱引用,其引用的对象计数器不会增加,且在对象释放时自动置为nil。weak的本质是通过哈希表实现,以引用对象地址为key,weak指针地址集合为value。实现过程分为初始化、添加引用和释放三个阶段。

2301_80253909的博客 1347

《网络安全自学教程》- OSI七层模型分层及作用,数据封装与解封过程,数据传输过程。

OSI分哪七层,每层的作用是什么,解释数据在七层模型中是怎样传输的,封包和解封过程,数据包在每一层是怎么封装和解封的。

wangyuxiang946的博客 1万+

【iOS开发】浅谈iOS之weak底层实现原理

浅谈iOS之weak底层实现原理

Hanrovey Blog 444

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

浅谈weak与unowned

iOS开发中,weak和unowned是解决循环引用的两种机制。Objective-C通过全局weak哈希表实现,对象销毁时自动置空weak指针;Swift则采用Sidetable方案,将weak引用计数分离存储,通过惰性置空机制延迟处理。unowned在Swift中会保持对象部分存活,访问时若对象已销毁会触发崩溃但避免野指针。虽然unowned性能略优,但weak更安全可靠,推荐优先使用weak,仅在必要时考虑unowned。两种方式都通过引入额外引用计数而非增加强引用来打破循环引用。

qq_63330040的博客 717

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

J_Knight_ iOS 高级面试题 基础题解答

最近从公司离职了,准备了一下接下来的面试,翻出了J_Knight的高级面试题复习了一下面试 iOS 基础题 分类和扩展有什么区别?可以分别用来做什么?分类有哪些局限性?分类的结构体里面有哪些成员? 区别: extension在编译期决议 它伴随类的产生而产生,亦随之一起消亡 category则完全不一样,它是在运行期决议的 extension可以添加实例变量,而category是无法添加实例...

weixin_34411563的博客 729

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

iOS开发:浅谈内存管理

内存分布 堆:一般由程序员分配释放,若程序员不释放,则可能会引起内存泄漏。其类似于链表。 栈:由编译器自动分配释放,存放函数的参数值,局部变量等值。其操作方式类似于数据结构中的栈。 内存管理原理 OC语言使用引用计数来管理内存,每个对象都有一个可以递增和递减的计数器。如果有其他对象持用该对象的话,那该对象就递增其引用计数;用完以后就递减其计数,当引用计数为0时,就销毁该对象。 MRC与ARC ...

ctguqsx的专栏 342

ios 添加block 类别_浅谈iOS之Block

前言iOS 4.0版本中,块不包含Objective-C中的新编程发现。 它们也存在于其他编程语言中(例如Javascript)和其他名称,例如Closures。 在iOS中,它们首次出现在4.0版本中,从那时起它们就已经被广泛接受和使用。 在随后的iOS版本中,Apple重新编写或更新了许多框架方法,因此它们采用了块,而且块似乎部分是代码编写方式的未来。 但他们到底有什么关系呢?块是添加到C,O...

weixin_34140828的博客 474

浅谈iOS内存管理

iOS手动内存管理和ARC

Jashion 586

浅谈iOS之Block

前言 iOS 4.0版本中,块不包含Objective-C中的新编程发现。 它们也存在于其他编程语言中(例如Javascript)和其他名称,例如Closures。 在iOS中,它们首次出现在4.0版本中,从那时起它们就已经被广泛接受和使用。 在随后的iOS版本中,Apple重新编写或更新了许多框架方法,因此它们采用了块,而且块似乎部分是代码编写方式的未来。 但他们到底有什么关系呢? 块是添加...

Future_One的专栏 515

iOS 浅谈Block外部的变量传递

背景介绍在iOS开发过程中,我们经常会用到block这个对象,它可以作为函数的回调、类的属性等出现在我们的项目中,作为回调,block相对于代理方法,代码量更少,使用起来更方便,还可以使用与block定义同一作用范围的变量。当然,block的使用会让代码的逻辑不如使用代理清晰,萝卜青菜,各有所爱。下面我就对于block可以使用与它在同一作用范围的变量这一特性展开说一下自己的理解。 正文先看这样一段代

夏日的博客 2399

华山论剑之浅谈iOS瀑布流

心灵鸡汤可不是谁想喝就喝的! --------------栋哥 看完千篇一律的UI布局之后,当我们看到瀑布流的布局是不是觉得有种耳目一新的感觉呢?今天我们就说一下如果实现瀑布流,对于瀑布流,现在iOS中总共存在着三种实现方法. 1.实现瀑布流的布局,我们需要计算每一张图片的尺寸大小,然后根据列数布局到我们的UIScrollView上去 2.UITableView实现瀑布流效果,就是每一列都是一个视图. 3.UICollectionView实现瀑布流就是对UICollectionView的Flow.

得不到的永远是骚栋. 1087

iOS之block浅谈

前言 ios4.0系统已开始支持block,在编程过程中,block被Obj-C看成是对象,它封装了一段代码,这段代码可以在任何时候执行。block可以作为函数参数或者函数的返回值,而其本身又可以带输入参数或返回值。它和传统的函数指针很类似,但是有区别:block是inline的,并且它对局部变量是只读的。 block和函数的相似性:(1)可以保存代码(2)有返回值(3)有形参(4)调用方

czkyes的博客 4102

ARC浅谈

1. Ownership Qualifiers __strong -- 不使用任何修饰符的情况下,默认是__strong。在ARC环境下,编译器会自动为__strong修饰的对象指针生成恰当的release代码,比如出了对象所属作用域,或者发生指针赋值时。__weak -- 使用__weak修饰符,编译器(准确说是Runtime System)会记录被修饰的指针,当指向对象被释放时,

MrLiuZhe'Blog 859

浅谈 AutoreleasePool 的实现原理

面试题: autorelease 对象什么时候释放。 autorelease 的本质就是延迟调用 release 方法 在 MRC 的环境下,可以通过调用 [obj autorelease] 将对象添加到当前的 autoreleasepool 中,来延迟释放内存; 在 ARC的环境下,当我们创建一个对象,可以通过 __autoreleasing 修饰符,会将对象添加到当前的 autorelease...

weixin_33929309的博客 791

华山论剑之浅谈iOS的 target - action设计模式 和 代理模式 以及Bolck

当我们觉得一件事情是理所当然的时候,那正是我们失去它的时候. target - action设计模式 和 代理模式 以及Bolck 不管是哪一个,都是我们在编程过程中比较常用的,但是真正有多少人还记得他们的实现原理的?今天我就浅谈一下target - action设计模式 和 代理模式 以及Bolck 这三个模块.在谈之前,我们先看一张搞笑的图片,让我们对三种模式有个初步的了解. target - action设计模式 target - action设计模式 是一种比较常见的设计模式,比如我们在用.

得不到的永远是骚栋. 675
上一篇: 浅谈iOS之Block
下一篇: 解决Xcode Simulator 黑屏问题
Flame_Dream
博客等级 码龄12年 35粉丝 82原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值