#### 講一下atomic的實現機制;為什么不能保證絕對的線程安全(最好可以結合場景來說)?
? 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方法獲取到返回值之前不會執行setter方法里的賦值代碼。但是出了getter方法和setter方法后就不能保證線程安全了,舉個例子:
? ```
@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 ;這個語句不是線程安全的,因為他可以分為三個指令:
? - 從內存中取出intA的值放到寄存器中;
? - 把寄存器中值加上某一個數;
? - 再把寄存器中得值放回內存中;
來觀察一下AB兩個線程交錯執行會發生什么:
1. A線程:讀取intA的放到一個寄存器A(0);
2. B線程:讀取intA的放到一個寄存器B(0);
3. A線程:將寄存器A的值加2(2);
4. B線程:將寄存器B的值加3(3);
5. A線程:將寄存器A的值加協會到內存,此時intA的值是2;
6. B線程:將寄存器B的寫回到內存,此時intA的值是3;
我們預期的結果是5,但實際返回的結果可能是最后寫入內存的那個值。
再舉個栗子:
```
@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里面可能會因為數組越界而引起crash,因為加入在B線程里判斷self.arr.count >= 2的時候數組是self.arr = @[@"1", @"2", @"3"];但是當調用[self.arr objectAtIndex:1]可能self.arr的值已經在線程A里被更改為了@[@"1"],此時數組越界了。因此,雖然self.arr是atomic的,還是會出現線程安全問題。
1.什么情況下使用weak關鍵詞,weak和assign有什么不同?
在ARC里,為了避免出現循環引用時,要使用weak關鍵詞,比如delegate和block;
在xib中的IBOutlet屬性,由于已經有了強引用,不需要再用stong關鍵詞;
weak修飾的屬性,在釋放時會置成nil,assign只是簡單地進行賦值操作;
weak只能用于OC對象,assign可用于非OC對象;
2.為什么NSString、NSArray和NSDictionary使用copy修飾而不用strong;
NSString、NSArray和NSDictionary有對應的可變類型NSMutableString、NSMUtableArray和NSMutableDictionary;當我們給設置方法賦新知識,比如NSArray類型的對象A,如果傳遞的是其子類NSMutableArray類型的B,使用strong修飾的A話只是對B進行了強引用,它們指向的是同一個對象,當B發生變化時,A其實也發生了變化;使用copy則會copy一份新的對象,B的改變不會影響到A。
3.block為什么要用copy修飾?
在MRC里,block里面的對象是在棧區的,使用copy修飾不把他們copy到堆區;在ARC里,編譯器會自動進行copy工作。
4.下面的代碼會有什么問題?
// .h文件
@property (nonatomic, copy) NSMutableArray * mutableArray;
// .m文件
NSMutableArray*array = [NSMutableArray arrayWithObjects:@1,@2,nil];
self.mutableArray = array;
[self.mutableArray removeObjectAtIndex:0];
因為關鍵詞是copy,所以復制后self.mutableArray是不可變對象,在調用NSMutableArray的方法時會造成崩潰。
5.如何使自定義的類支持copy
自定義的類需要遵守NSCopying協議,如果類分為可變版本和不可變版本,需要遵守NSMutableCopying協議;
6.@property的本質是什么?
@property = ivar(實例變量) + setter + getter
可以把屬性當做一種關鍵字,編譯器會自動生成存取方法,并且向類中自動添加適當的實例變量,并且在屬性名前添加下劃線。
7. @protocol 和 category 中如何使用 @property
在 protocol 中使用 property 只會生成 setter 和 getter 方法聲明,我們使用屬性的目的,是希望遵守我協議的對象能實現該屬性
category 使用 @property 也是只會生成 setter 和 getter 方法的聲明,如果我們真的需要給 category 增加屬性的實現,需要借助于運行時的兩個函數:
objc_setAssociatedObject
objc_getAssociatedObject
8.@property中有那些關鍵字
原子性--nonatomic,atomic;
讀寫權限--readonly(只讀)readwrite(讀寫)
內存管理--assign,weak,strong,copy unsafe_unretained
方法名--setter,getter
9. ARC下,不顯式指定任何屬性關鍵字時,默認的關鍵字都有哪些?
對應基本數據類型默認關鍵字是
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的推薦用是用一個公用的HTTPClient,使用公用的URL,把網絡請求就的參數傳遞到HTTPClient的靜態方法里,最后通過block回調把網絡請求的數據回調出來。
ASI的用法更傳統,使用時要初始化一個ASIHTTPRequest實例,通過這個實例來配置網絡請求的參數,用代理或block進行數據回調。
ASI的直接操作對象ASIHTTPRequest是NSOPeration的子類,在異步請求處理的時候,在調用startAsynchronous方法后會把對象放入到共享的操作隊列,所有的操作都是在這個對象所處的子線程中完成的。
11.網絡優化:
1)減小數據請求大小,對于post請求,Body可以做gzip壓縮;使用專門的算法對于音視頻,圖片進行壓縮;
2)精簡數據格式,使用json替代xml;
3)根據不同的設備返回不同分辨率的圖片;
4)緩存數據,在一定有效的時間內再次請求時直接取緩存;
5)對較大的文件,可以考慮多連接;
#####HTTP冪等性
HTTP方法的冪等性是指一次和多次請求某一個資源應該具有同樣的副作用