總結(jié)

#### 講一下atomic的實(shí)現(xiàn)機(jī)制;為什么不能保證絕對的線程安全(最好可以結(jié)合場景來說)?


? runtime里的源碼:

? getter方法

? ```

? id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) {

? ? 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);

}

? ```

? setter方法:

? ```

? static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy)

{

? ? if (offset == 0) {

? ? ? ? object_setClass(self, newValue);

? ? ? ? return;

? ? }

? ? id oldValue;

? ? id *slot = (id*) ((char*)self + offset);

? ? if (copy) {

? ? ? ? newValue = [newValue copyWithZone:nil];

? ? } else if (mutableCopy) {

? ? ? ? newValue = [newValue mutableCopyWithZone:nil];

? ? } else {

? ? ? ? if (*slot == newValue) return;

? ? ? ? newValue = objc_retain(newValue);

? ? }


? ? if (!atomic) {

? ? ? ? oldValue = *slot;

? ? ? ? *slot = newValue;

? ? } else {

? ? ? ? spinlock_t& slotlock = PropertyLocks[slot];

? ? ? ? slotlock.lock();

? ? ? ? oldValue = *slot;

? ? ? ? *slot = newValue;? ? ? ?

? ? ? ? slotlock.unlock();

? ? }

? ? objc_release(oldValue);

}

? ```

? 從上面可以看出,使用atomic之后,在setter和getter方法里會使用自旋鎖spinlock_t來保證setter方法和getter方法的線程的安全,可以看做getter方法獲取到返回值之前不會執(zhí)行setter方法里的賦值代碼。但是出了getter方法和setter方法后就不能保證線程安全了,舉個(gè)例子:

? ```

@property (atomic, assign)? ? int? ? ? intA;//初始值是0

//thread A

? ? self.intA = self.intA + 2 ;


//thread B

? ? self.intA = self.intA + 3;

? ```

? 上面的例子,雖然settr和getter方法是線程安全的,但是 self.intA = self.intA + 2 ;這個(gè)語句不是線程安全的,因?yàn)樗梢苑譃槿齻€(gè)指令:

? - 從內(nèi)存中取出intA的值放到寄存器中;

? - 把寄存器中值加上某一個(gè)數(shù);

? - 再把寄存器中得值放回內(nèi)存中;

來觀察一下AB兩個(gè)線程交錯(cuò)執(zhí)行會發(fā)生什么:

1. A線程:讀取intA的放到一個(gè)寄存器A(0);

2. B線程:讀取intA的放到一個(gè)寄存器B(0);

3. A線程:將寄存器A的值加2(2);

4. B線程:將寄存器B的值加3(3);

5. A線程:將寄存器A的值加協(xié)會到內(nèi)存,此時(shí)intA的值是2;

6. B線程:將寄存器B的寫回到內(nèi)存,此時(shí)intA的值是3;

我們預(yù)期的結(jié)果是5,但實(shí)際返回的結(jié)果可能是最后寫入內(nèi)存的那個(gè)值。

再舉個(gè)栗子:

```

@property (atomic, strong) NSArray*? ? ? ? ? ? ? ? arr;

//thread A

for (int i = 0; i < 100000; i ++) {

? ? if (i % 2 == 0) {

? ? ? ? self.arr = @[@"1", @"2", @"3"];

? ? }

? ? else {

? ? ? ? self.arr = @[@"1"];

? ? }

? ? NSLog(@"Thread A: %@\n", self.arr);

}

//thread B

for (int i = 0; i < 100000; i ++) {

? ? if (self.arr.count >= 2) {

? ? ? ? NSString* str = [self.arr objectAtIndex:1];

? ? }

? ? NSLog(@"Thread B: %@\n", self.arr);

}

```

上面的例子線程B里面可能會因?yàn)閿?shù)組越界而引起crash,因?yàn)榧尤朐贐線程里判斷self.arr.count >= 2的時(shí)候數(shù)組是self.arr = @[@"1", @"2", @"3"];但是當(dāng)調(diào)用[self.arr objectAtIndex:1]可能self.arr的值已經(jīng)在線程A里被更改為了@[@"1"],此時(shí)數(shù)組越界了。因此,雖然self.arr是atomic的,還是會出現(xiàn)線程安全問題。



1.什么情況下使用weak關(guān)鍵詞,weak和assign有什么不同?

在ARC里,為了避免出現(xiàn)循環(huán)引用時(shí),要使用weak關(guān)鍵詞,比如delegate和block;

在xib中的IBOutlet屬性,由于已經(jīng)有了強(qiáng)引用,不需要再用stong關(guān)鍵詞;

weak修飾的屬性,在釋放時(shí)會置成nil,assign只是簡單地進(jìn)行賦值操作;

weak只能用于OC對象,assign可用于非OC對象;

2.為什么NSString、NSArray和NSDictionary使用copy修飾而不用strong;

NSString、NSArray和NSDictionary有對應(yīng)的可變類型NSMutableString、NSMUtableArray和NSMutableDictionary;當(dāng)我們給設(shè)置方法賦新知識,比如NSArray類型的對象A,如果傳遞的是其子類NSMutableArray類型的B,使用strong修飾的A話只是對B進(jìn)行了強(qiáng)引用,它們指向的是同一個(gè)對象,當(dāng)B發(fā)生變化時(shí),A其實(shí)也發(fā)生了變化;使用copy則會copy一份新的對象,B的改變不會影響到A。

3.block為什么要用copy修飾?

在MRC里,block里面的對象是在棧區(qū)的,使用copy修飾不把他們copy到堆區(qū);在ARC里,編譯器會自動進(jìn)行copy工作。

4.下面的代碼會有什么問題?

// .h文件

@property (nonatomic, copy) NSMutableArray * mutableArray;

// .m文件

NSMutableArray*array = [NSMutableArray arrayWithObjects:@1,@2,nil];

self.mutableArray = array;

[self.mutableArray removeObjectAtIndex:0];

因?yàn)殛P(guān)鍵詞是copy,所以復(fù)制后self.mutableArray是不可變對象,在調(diào)用NSMutableArray的方法時(shí)會造成崩潰。

5.如何使自定義的類支持copy

自定義的類需要遵守NSCopying協(xié)議,如果類分為可變版本和不可變版本,需要遵守NSMutableCopying協(xié)議;

6.@property的本質(zhì)是什么?

@property = ivar(實(shí)例變量) + setter + getter

可以把屬性當(dāng)做一種關(guān)鍵字,編譯器會自動生成存取方法,并且向類中自動添加適當(dāng)?shù)膶?shí)例變量,并且在屬性名前添加下劃線。


7. @protocol 和 category 中如何使用 @property

在 protocol 中使用 property 只會生成 setter 和 getter 方法聲明,我們使用屬性的目的,是希望遵守我協(xié)議的對象能實(shí)現(xiàn)該屬性

category 使用 @property 也是只會生成 setter 和 getter 方法的聲明,如果我們真的需要給 category 增加屬性的實(shí)現(xiàn),需要借助于運(yùn)行時(shí)的兩個(gè)函數(shù):

objc_setAssociatedObject

objc_getAssociatedObject

8.@property中有那些關(guān)鍵字

原子性--nonatomic,atomic;

讀寫權(quán)限--readonly(只讀)readwrite(讀寫)

內(nèi)存管理--assign,weak,strong,copy unsafe_unretained

方法名--setter,getter

9. ARC下,不顯式指定任何屬性關(guān)鍵字時(shí),默認(rèn)的關(guān)鍵字都有哪些?

對應(yīng)基本數(shù)據(jù)類型默認(rèn)關(guān)鍵字是

atomic,readwrite,assign

對于普通的 Objective-C 對象

atomic,readwrite,strong

10.ASI和AFN的對比

http://www.infoq.com/cn/articles/afn_vs_asi

ASI是基于CFNetwork的, 而AFN是基于NSURL的,從性能上來說ASI要好一些。

AFN的推薦用是用一個(gè)公用的HTTPClient,使用公用的URL,把網(wǎng)絡(luò)請求就的參數(shù)傳遞到HTTPClient的靜態(tài)方法里,最后通過block回調(diào)把網(wǎng)絡(luò)請求的數(shù)據(jù)回調(diào)出來。

ASI的用法更傳統(tǒng),使用時(shí)要初始化一個(gè)ASIHTTPRequest實(shí)例,通過這個(gè)實(shí)例來配置網(wǎng)絡(luò)請求的參數(shù),用代理或block進(jìn)行數(shù)據(jù)回調(diào)。

ASI的直接操作對象ASIHTTPRequest是NSOPeration的子類,在異步請求處理的時(shí)候,在調(diào)用startAsynchronous方法后會把對象放入到共享的操作隊(duì)列,所有的操作都是在這個(gè)對象所處的子線程中完成的。

11.網(wǎng)絡(luò)優(yōu)化:

1)減小數(shù)據(jù)請求大小,對于post請求,Body可以做gzip壓縮;使用專門的算法對于音視頻,圖片進(jìn)行壓縮;

2)精簡數(shù)據(jù)格式,使用json替代xml;

3)根據(jù)不同的設(shè)備返回不同分辨率的圖片;

4)緩存數(shù)據(jù),在一定有效的時(shí)間內(nèi)再次請求時(shí)直接取緩存;

5)對較大的文件,可以考慮多連接;


#####HTTP冪等性

HTTP方法的冪等性是指一次和多次請求某一個(gè)資源應(yīng)該具有同樣的副作用

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

相關(guān)閱讀更多精彩內(nèi)容

  • 一、深復(fù)制和淺復(fù)制的區(qū)別? 1、淺復(fù)制:只是復(fù)制了指向?qū)ο蟮闹羔?,即兩個(gè)指針指向同一塊內(nèi)存單元!而不復(fù)制指向?qū)ο蟮?..
    iOS_Alex閱讀 1,531評論 1 27
  • 一.OC的三大特性 封裝、繼承、多態(tài) 1> 什么是多態(tài) 多態(tài):不同對象以自己的方式響應(yīng)相同的消息的能力叫做多態(tài)。 ...
    藍(lán)心兒的藍(lán)色之旅閱讀 1,514評論 0 2
  • 1、在UIScorllView上添加UISlide,拖動slide的時(shí)候,scrollerview會跟著動,解決方...
    渡邊君WM閱讀 3,532評論 5 21
  • 把網(wǎng)上的一些結(jié)合自己面試時(shí)遇到的面試題總結(jié)了一下,以后有新的還會再加進(jìn)來。 1. OC 的理解與特性 OC 作為一...
    AlaricMurray閱讀 2,667評論 0 20
  • 1.即使你不是天才,做好準(zhǔn)備工作也會讓你看起來像個(gè)天才! 不論做任何事情,提前做好準(zhǔn)備工作就不至于讓你感覺到慌亂。...
    梓毓爸閱讀 284評論 0 0

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