IOS @autoreleasepool

??好的!今天我們來練習(xí)IOS,研究一下@autoreleasepool塊到底做了哪些事情。

自動釋放池

?? 在使用MRC管理內(nèi)存的時候,我們可以這樣創(chuàng)建一個自動釋放池并添加對象到自動釋放池,自動釋放池被銷毀后會向所有添加到池內(nèi)的對象發(fā)送釋放消息,代碼中也就是向obj0和obj1兩個局部對象發(fā)送釋放消息。

- (void)cerateAutoreleasepool {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];//創(chuàng)建自動釋放池
    id obj0 = [[NSObject alloc] init];
    id obj1 = [[NSObject alloc] init];
    [obj0 autorelease];
    [obj1 autorelease];
    [pool drain];
}

??在ARC中,我們使用@autoreleasepool代碼塊實(shí)現(xiàn)自動釋放池,我個人的理解是放入@autoreleasepool代碼塊的對象會被添加到自動釋放池,也就是隱性的調(diào)用了autorelease,所以下面的代碼跟上面的其實(shí)是一個意思,當(dāng)離開@autoreleasepool代碼塊的時候,obj0和obj1收到了釋放的消息。

- (void)cerateAutoreleasepool {
    @autoreleasepool {
        id obj0 = [[NSObject alloc] init];
        id obj1 = [[NSObject alloc] init];
    }
}
案例

??以下的例子是我在實(shí)際工作中所碰到的一個問題,之前有一個需求是對一個有12個分頁的UIScrollView進(jìn)行截圖,要求是從第一個分頁開始截取,截完第二個,把第二個拼接在第一個下面,以此類推,拼接完12個頁面,以下是截圖與拼接的代碼。

- (UIImage *)screenShot {
    UIGraphicsBeginImageContextWithOptions(self.view.frame.size, YES, 0.0);
    [self.view drawViewHierarchyInRect:self.view.frame afterScreenUpdates:YES];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}

- (UIImage *)addSlaveImage:(UIImage *)slaveImage toMasterImage:(UIImage *)masterImage {
    CGSize size;
    size.width = masterImage.size.width;
    size.height = masterImage.size.height + slaveImage.size.height;
    UIGraphicsBeginImageContextWithOptions(size, YES, 0.0);
    [masterImage drawInRect:CGRectMake(0, 0, masterImage.size.width, masterImage.size.height)];
    [slaveImage drawInRect:CGRectMake(0, masterImage.size.height, masterImage.size.width, slaveImage.size.height)];
    UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return resultImage;
}

- (UIImage *)imageFromStitchingNotUseAutoreleasepool {
    UIImage *resultImage = [self screenShot];
    for(int i = 0; i <= 12; i++) {
        UIImage *screenShotImage = [self screenShot];
        resultImage = [self addSlaveImage:screenShotImage toMasterImage:resultImage];
    }
    return resultImage;
}

??但是問題出現(xiàn)了,在截圖與拼接圖片的時候,UIGraphicsBeginImageContextWithOptions需要申請內(nèi)存,特別是在拼接到12張圖片的時候,需要申請的內(nèi)存已經(jīng)變得很大,如果是在老一點(diǎn)的機(jī)器上面就直接奔潰了,這時就需要用到@autoreleasepool代碼塊來優(yōu)化。

- (UIImage *)imageFromStitchingUseAutoreleasepool {
    UIImage *resultImage = [self screenShot];
    for(int i = 0; i <= 12; i++) {
        //在這里添加 autoreleasepool
        @autoreleasepool {
            UIImage *screenShotImage = [self screenShot];
            resultImage = [self addSlaveImage:screenShotImage toMasterImage:resultImage];
        }
    }
    return resultImage;
}

??我個人的理解是在未添加@autoreleasepool代碼塊前,每次截圖都會有一個screenShotImage局部對象留在內(nèi)存中,這些對象在imageFromStitching方法結(jié)束生命周期才會被釋放,之后我添加了@autoreleasepool 代碼塊,把screenShotImage都放進(jìn)autoreleasepool,每次循環(huán)創(chuàng)建的screenShotImage都會在離開@autoreleasepool{ }之后被釋放而不是等到函數(shù)結(jié)束再釋放,這樣可以將一些臨時對象盡早的釋放掉,大大減少內(nèi)存的峰值,以下是我用xcode的Leaks工具測試的結(jié)果。

未使用@autoreleasepool內(nèi)存峰值變化
NotUseAutoreleasepool.jpg
使用@autoreleasepool后內(nèi)存峰值變化

UseAutoreleasepool.jpg

??好,問題到這里算是勉強(qiáng)解決了,當(dāng)然以上對autoreleasepool的理解只是個人的見解,如有錯誤請指出,對于截圖拼接的方法,也肯定會有大神有更好的方法去優(yōu)化(如果有的話請?jiān)u論告訴我),最后謝謝大家觀看?。?!??
最后,完整代碼鏈接:https://github.com/arrosev/IOSTestProjectCollection

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容