[※]@property中有哪些屬性關鍵字?php
1.原子性nonatomic/automiccss
在默認狀況下,由編譯器合成的方法會經過鎖定機制確保其原子性(automicity),若是具有nonatomic特質,則不使用同步鎖.html
2.讀/寫權限 readwrite/readonlyios
3.內存管理語義c++
assign "設置方法"只會針對"純量類型" (cgfloat,nsinterger等)的簡單賦值操做.程序員
strong "擁有關係"爲這種屬性設置新值時,設置方法先保留新值,並釋放舊址,而後再將新值設置上去. (保新去舊)web
weak "非擁有關係"爲這種屬性賦新值時,設置方法既不保留新值,也不釋放舊值.此特性和assign相似,然而屬性所指的對象遭到摧毀時,屬性也會被清空.面試
unsafe_unretained 此特質的語義和assign相同,可是他適合於"對象類型",該特質表達一種非擁有關係,當對象遭到摧毀時,屬性值不會自動清空,這一點和weak有區別.objective-c
copy 此特質所表達的所屬關係於strong相似,然而設置方法並不保存新值,而是將其"拷貝".拷貝算法
4.方法名
getter=<name>
@property(nonatomic,getter = isOn)BOOL on;自定義方法名
setter=<name> 不是特別經常使用.
[※]weak屬性須要在dealloc中置nil麼?
不須要,在ARC環境不管是強指針仍是弱指針都無需在deallco設置爲nil,ARC會自動幫咱們處理強指針strong 和弱指針weak
1.有了ARC,咱們的代碼能夠清晰不少,你再也不須要考慮何時retain或release對象。惟一須要考慮的是對象之間的關聯,也就是(哪一個對象擁有哪一個對象) 對象的擁有關係,根據擁有關係來處理對應的retainCount值.
2.ARC也有一些限制:
1> 首先ARC只能工做於Objective-C對象,若是應用使用了Core Foundation或malloc()/free(),此時仍是須要你來手動管理內存
2> 此外ARC還有其它一些更爲嚴格的語言規則,以確保ARC可以正常地工做
3.雖然ARC管理了retain和release,但並不表示你徹底不須要關心內存管理的問題。由於strong指針會保持對象的生命,某些狀況下你仍然須要手動設置這些指針爲nil,不然可能致使應用內存不足。不管什麼時候你建立一個新對象時,都須要考慮誰擁有該對象,以及這個對象須要存活多久
4.ARC還能很好地結合C++使用,這對遊戲開發是很是有幫助的。對於iOS 4,ARC有一點點限制(不支持weak指針),但也沒太大關係
ARC注意事項
1.不能直接調用dealloc方法,不能調用retain,release,autorelease,retainCount方法,包括@selector(retain)的方式也不行
2.能夠用dealloc方法來管理一些資源,但不能用來釋放實例變量,也不能在dealloc方法裏面去掉[super dealloc]方法,在ARC下父類的dealloc一樣由編譯器來自動完成
3.Core Foundation類型的對象仍然能夠用CFRetain,CFRelease這些方法
4.不能再使用NSAllocateObject和NSDeallocateObject對象
5.不能在C結構體中使用對象指針,若是有相似功能能夠建立一個Objective-C類來管理這些對象
6.在id和void*之間沒有簡便的轉換方法,一樣在Objective-C和Core Foundation類型之間的轉換都須要使用編譯器指定的轉換函數
7.不能再使用NSAutoreleasePool對象,ARC提供了@autoreleasepool塊來代替它,這樣更有效率
8.不能使用內存存儲區(不能再使用NSZone)
9.不能以new爲開頭給一個屬性命名
10.聲明IBOutlet時通常應當使用weak,除了對StoryBoard這樣nib中間的頂層對象要用strong
11.weak至關於老版本的assign,strong至關於retain
@property 後面能夠有哪些修飾符?
線程安全的:
atomic,nonatomic
訪問權限的
readonly,readwrite
內存管理(ARC)
assign,strong,weak,copy
內存管理(MRC)
assign,retain,copy
指定方法名稱
setter=
getter=
什麼狀況使用 weak 關鍵字,相比 assign有什麼不一樣?好比:
在ARC中,出現循環引用的時候,必需要有一端使用weak,好比:自定義View的代理屬性
已經自身已經對它進行一次強應用,沒有必要在強引用一次,此時也會使用weak,自定義View的子控件屬性通常也使用weak;但b是也可使用strong
weak當對象銷燬的時候,指針會被自動設置爲nil,而assign不會* assigin 能夠用非OC對象,而weak必須用於OC對象
怎麼用 copy 關鍵字?
對於字符串和block的屬性通常使用copy
字符串使用copy是爲了外部把字符串內容改了,影響該屬性達到賦值的目的
block使用copy是在MRC遺留下來的,在MRC中,方法內部的block是在在棧區的,使用copy能夠把它放到堆區.在ACR中對於block使用copy仍是strong效果是同樣的
這個寫法會出什麼問題: @property (copy) NSMutableArray *array;
添加,刪除,修改數組內的元素的時候,程序會由於找不到對於的方法而崩潰.由於copy就是複製一個不可變NSArray的對象 copy對象出來的是不可變的數組
如何讓本身的類用 copy 修飾符?
你是說讓個人類也支持copy的功能嗎?
若是面試官說是:
遵照NSCopying協議
實現 - (id)copyWithZone:(NSZone *)zone;方法
若是面試官說否,是屬性中如何使用copy
在使用字符串和block的時候通常都使用copy
字符串使用copy是爲了外部把字符串內容改了,影響該屬性達到賦值的目的
block使用copy是在MRC遺留下來的,在MRC中,方法內部的block是在在棧區的,使用copy能夠把它放到堆區.在ACR中對於block使用copy仍是strong效果是同樣的(C函數是在棧區,OC對象是在堆區)
如何重寫帶 copy 關鍵字的 setter?
重寫copy的setter方法時候,必定要調用一下傳入的對象的copy方法,而後在賦值給該setter的方法對應的成員變量
@property 的本質是什麼?ivar、getter、setter是如何生成並添加到這個類中的
(生成5個記錄屬性來記錄具體的實現過程分別是對象偏移量OBJC_IVAR_$ ,setter和getter方法,iVar_list成員變量列表,method_list列表,prop_list列表)
在普通的OC對象中,@property就是編譯其自動幫咱們生成一個私有的成員變量和setter與getter方法的聲明和實現
我爲了搞清屬性是怎麼實現的,曾經反編譯過相關的代碼,他大體生成了五個個東西
OBJC_IVAR_$類名$屬性名稱該屬性的偏移量
setter與getter方法對應的實現函數
ivar_list 就是成員變量列表
method_list 方法列表
prop_list 屬性列表
也就是說咱們每次在增長一個屬性,系統都會在ivar_list中添加一個成員變量的描述,在method_list中增長setter與getter方法的描述,在屬性列表中增長一個屬性的屬性的描述,而後計算該屬性在對象中的偏移量,而後伸出setter與getter方法對應的實現,在setter方法方法中從偏移量的位置開始賦值,在getter方法中從偏移量開始取值,爲了可以讀取正確字節數,系統對象偏移量的指針類型進行了類型強轉.
@protocol 和 category中如何使用 @property
在protocol 使用@property只會生成setter和getter方法聲明,咱們使用屬性的目的,是但願遵照指定協議的對象的實現該屬性對應的方法
在category 使用@property也是隻會生成setter和getter方法的聲明,若是咱們真的須要給category增長屬性的實現,須要藉助於運行時的兩個函數
objc_setAssociatedObject 動態賦值加載
objc_getAssociatedObject 動態取值加載
runtime 如何實現 weak屬性
runtime 對註冊的類,會進行佈局,對於weak對象會放入一個hash表中。用weak指向的對象地址做爲key,當此對象的引用計數爲0的時候會dealloc,進而在這個 weak表中找到此對象地址爲鍵的全部weak對象,從而設置爲nil;
[※※]@synthesize和@dynamic分別有什麼做用?
@property有兩個對應的詞,一個是@synthesize,一個是@dynamic。若是@synthesize和@dynamic都沒寫,那麼默認的就是@syntheszie var = _var;
@synthesize的語義是若是你沒有手動實現setter方法和getter方法,那麼編譯器會自動爲你加上這兩個方法。
@dynamic告訴編譯器,屬性的setter與getter方法由用戶本身實現,不自動生成。(固然對於readonly的屬性只需提供getter便可(不能夠修改,只能夠讀取))。假如一個屬性被聲明爲@dynamic var,而後你沒有提供@setter方法和@getter方法,編譯的時候沒問題,可是當程序運行到instance.var =someVar,因爲缺setter方法會致使程序崩潰;或者當運行到 someVar = var時,因爲缺getter方法一樣會致使崩潰。編譯時沒問題,運行時才執行相應的方法,這就是所謂的動態綁定。經常使用於動態綁定
[※※※]ARC下,不顯示指定任何屬性關鍵字時,默認的關鍵字都有哪些?
對應基本數據類型默認關鍵字是
atomic,readwrite,assign
對於普通的OC對象
atomic,readwrite,strong
原子屬性(做用:經過鎖定機制來保持原子性)讀寫屬性(readwrite 可讀可寫屬性) assign賦值屬性非擁有關係 strong擁有關係屬性
[※※※]用@property聲明的NSString(或NSArray,NSDictionary)常用copy關鍵字,爲何?若是改用strong關鍵字,可能形成什麼問題?
由於父類指針能夠指向子類對象,使用copy的目的是爲了讓本對象的屬性不受外界影響,使用copy不管給我傳入是一個可變對象仍是不可對象,我自己持有的就是一個不可變的副本. (關鍵字:副本不可變 保持對象不受外界影響)
若是咱們使用是strong,那麼這個屬性就有可能指向一個可變對象,若是這個可變對象在外部被修改了,那麼會影響該屬性. (關鍵字:可能指向可變的對象,外界改變會影響屬性);
[※※※]@synthesize合成實例變量的規則是什麼?假如property名爲foo,存在一個名爲_foo的實例變量,那麼還會自動合成新變量麼?
若是沒有指定成員變量的名稱與自動生成一個屬性同名的成員變量(注意:無指明生成同名),若是指定的成員變量的名稱,會生成一個指定的名稱的成員變量,若是這個成員已經存在了就再也不生成了.
若是是 @synthesize foo;還會生成一個名稱爲foo的成員變量
若是是 @synthesize foo = _foo;就不會生成成員變量了. 其實默認的生成是: _變量名
[※※※※※]在有了自動合成屬性實例變量以後,@synthesize還有哪些使用場景?
@synthesize主要就是用來生成setter,getter方法的實現,在@property被加強以後,其實已經不多使用@synthesize了.
[※※]objc中向一個nil對象發送消息將會發生什麼?
在Objective-C中向nil發送消息是徹底有效的 ——只是在運行時不會有任何做用.
若是一個方法返回值是一個對象,那麼發送給nil的消息將返回0(nil)。例如:Person *motherInlaw = [aPerson spouse] mother];若是spouse對象爲nil,那麼發送給nil的消息mother也將返回nil。
若是方法返回值爲指針類型,其指針大小爲小於或者等於sizeof(void*),float,double,long double 或者long long的整型標量,發送給nil的消息將返回0。
若是方法返回值爲結構體,發送給nil的消息將返回0。結構體中各個字段的值將都是0。
若是方法的返回值不是上述提到的幾種狀況,那麼發送給nil的消息的返回值將是未定義的。
[※※※]objc中向一個對象發送消息[obj foo]和objc_msgSend()函數之間有什麼關係?
該方法編譯以後就是objc_msgSend()函數調用.若是我沒有記錯的大概是這樣的.
((void ()(id, SEL))(void )objc_msgSend)((id)obj, sel_registerName("foo"));
[※※※]何時會報unrecognized selector的異常?
當使用該對象上某個方法,而該對象上沒有實現這個方法的時候此時會閃退
[※※※※]一個objc對象如何進行內存佈局?(考慮有父類的狀況)
全部父類的成員變量和本身的成員變量都會存放在該對象所對應的存儲空間中.
每個對象內部都一個isA指針,指向他的類對象,類對象中存放着本對象的對象方法列表和成員變量的列表,屬性列表,它內部也有一個isA指針指向元對象(meta class),元對象內部存放的是類方法列表,類對象內部還有一個superclass的指針,指向他的父類對象.
根對象就是NSobject
[※※※※]一個objc對象的isa的指針指向什麼?有什麼做用?
指向他的類對象,從而能夠找到對象上的方法每個對象內部都一個isA指針,指向他的類對象,類對象中存放着本對象的對象方法列表和成員變量的列表,屬性列表,它內部也有一個isA指針指向元對象(meta class),元對象內部存放的是類方法列表,類對象內部還有一個superclass的指針,指向他的父類對象.
[※※※※]下面的代碼輸出什麼?
@implementation Son : Father
- (id)init {
self = [super init];
if (self) {
NSLog(@"%@", NSStringFromClass([self class]));
NSLog(@"%@", NSStringFromClass([super class]));
這裏面的super是一個實力對象
}
return self;
}
@end
輸出的結果都是:Son,
緣由:super和self都是指向的本實例對象的,
不一樣的是,super調用的跳過本類方法,調用父類的方法
父類方法的class方法原本都是在基類中實現的,因此不管使用self和super調用都是同樣的.
具體分析參照刨根問底Objective-C Runtime(1)- Self & Super
[※※※※]使用runtime Associate方法關聯的對象,須要在主對象dealloc的時候釋放麼?
在ARC下不須要編譯器可以幫組咱們來完成
在MRC中,對於使用retain或copy策略的須要
[※※※※※]objc中的類方法和實例方法有什麼本質區別和聯繫?
類方法
類方法是屬於類對象的
類方法只能經過類對象調用
類方法中的self是類對象
類方法能夠調用其餘的類方法
類方法中不能訪問成員變量
類方法中不定直接調用對象方法
實例方法
實例方法是屬於實例對象的
實例方法只能經過實例對象調用
實例方法中的self是實例對象
實例方法中能夠訪問成員變量
實例方法中直接調用實例方法
實例方法中也能夠調用類方法(經過類名)
[※※※※]runtime如何經過selector找到對應的IMP地址?(分別考慮類方法和實例方法)
每個類對象中都一個方法列表,方法列表中記錄着方法的名稱,方法實現,以及參數類型,其實selector本質就是方法名稱,經過這個方法名稱就能夠在方法列表中找到對應的方法實現.(關鍵字:方法列表 @selector本質是方法名稱)
函數指針, 用於表示對象方法的實現 typedef id ( *IMP ) ( id , SEL , . . . ) ;
id 指代objc中的對象,每一個對象的在內存的結構並非肯定的,但其首地址指向的確定是isa。經過isa指針,運行時就能獲取到objc_class。
IMP 是一個函數指針。objc中的方法最終會被轉換成純C的函數,IMP就是爲了表示這些函數的地址。
[※※※※※]_objc_msgForward函數是作什麼的,直接調用它將會發生什麼?
首先了解objc_msgSend
obj_msgSend的實際動做就是:找到這個函數指針,而後調用它。
objc_msgSend的動做比較清晰:首先在Class中的緩存查找imp函數指針(沒緩存則初始化緩存),若是沒找到,則向父類的Class查找。若是一直查找到NSObject根類仍舊沒有實現,則用_objc_msgForward函數指針代替imp。最後,執行這個imp函數指針。
_objc_msgForward是用於消息轉發的。這個函數的實現並無在objc-runtime的開源代碼裏面,而是在Foundation框架裏面實現的。加上斷點啓動程序後,會發現__CFInitialize這個方法會調用objc_setForwardHandler函數來註冊一個實現。當向一個對象發送一條消息,但它並無實現的時候,_objc_msgForward會嘗試作消息轉發。爲了展現消息轉發的具體動做,這裏嘗試向一個對象發送一條錯誤的消息,並查看一下_objc_msgForward是如何進行轉發的。結合NSObject文檔能夠知道,_objc_msgForward消息轉發作了以下幾件事:
1.調用resolveInstanceMethod:方法,容許用戶在此時爲該Class動態添加實現。若是有實現了,則調用並返回。若是仍沒實現,繼續下面的動做。
2.調用forwardingTargetForSelector:方法,嘗試找到一個能響應該消息的對象。若是獲取到,則直接轉發給它。若是返回了nil,繼續下面的動做。
3.調用methodSignatureForSelector:方法,嘗試得到一個方法簽名。若是獲取不到,則直接調用doesNotRecognizeSelector拋出異常。
4.調用forwardInvocation:方法,將地3步獲取到的方法簽名包裝成Invocation傳入,如何處理就在這裏面了。
上面這4個方法均是模板方法,開發者能夠override,由runtime來調用。最多見的實現消息轉發,就是重寫方法3和4,吞掉一個消息或者代理給其餘對象都是沒問題的。
id objc_msgSend(id self, SEL op, ...) {
if (!self) return nil;
IMP imp = class_getMethodImplementation(self->isa, SEL op);
imp(self, op, ...); //調用這個函數,僞代碼...
}
//查找IMP
IMP class_getMethodImplementation(Class cls, SEL sel) {
if (!cls || !sel) return nil;
IMP imp = lookUpImpOrNil(cls, sel);
if (!imp) return _objc_msgForward; //這個是用於消息轉發的
return imp;
}
IMP lookUpImpOrNil(Class cls, SEL sel) {
if (!cls->initialize()) {
_class_initialize(cls);
}
Class curClass = cls;
IMP imp = nil;
do { //先查緩存,緩存沒有時重建,仍舊沒有則向父類查詢
if (!curClass) break;
if (!curClass->cache) fill_cache(cls, curClass);
imp = cache_getImp(curClass, sel);
if (imp) break;
} while (curClass = curClass->superclass);
return imp;
}
[※※※※※]runtime如何實現weak變量的自動置nil?
2. 我猜系統會維護一個弱指針列表,當某個對象銷燬時候,它會把全部指向該對象的弱指針設置爲nil
ARC 的實現
蘋果的官方說明中稱,ARC是「由編譯器進行內存管理」的,但實際上只有編譯器是沒法徹底勝任的,ARC還依賴OC運行時庫,也就是說ARC是經過如下工具、庫來實現的:
● clang (LLVM 編譯器)3.0以上
● objc4 OC運行時庫 493.9以上
若是按照蘋果的說明,僅僅是編譯器管理內存的,那麼__weak修飾符也能夠在iOS 4中使用
__weak 修飾符
就像咱們知道的那樣__weak修飾符提供瞭如同魔法般的公能。
● 若使用__weak修飾符的變量引用對象被廢棄時,則將nil賦值給該變量
● 使用附有__weak修飾符的變量,就是使用註冊到autoreleasepool的對象。
咱們來看看它的實現:
{
id __weak obj_weak = obj;//obj已被賦值,而且是strong類型的
}
/*編譯器的模擬代碼*/
id obj_weak;
objc_initWeak(&obj_weak,obj);//初始化附有__weak修飾符的變量
objc_destroyWeak(&obj_weak);//釋放該變量
其中objc_initWeak objc_destroyWeak都是調用了objc_storeWeak函數,因此,上面的代碼能夠轉化爲下面的代碼
id obj_weak;
obj_weak = 0;
objc_storeWeak(&obj_weak,obj);
objc_storeWeak(&obj,0);
objc_storeWeak函數以把obj的地址做爲鍵值,obj_weak的地址做爲值存放到weak表(weak是一個hash表)中。
釋放對象時,廢棄對象的同時,程序的動做是怎樣的呢?對象經過objc_release釋放。
1. objc_release
2. 由於引用計數爲0因此執行dealloc
3. _objc_rootDealloc
4. object_dispose
5. objc_destructInstance
6. objc_clear_deallocating
而,調用objc_clear_deallocating的動做以下:
1. 從weak表中獲取廢棄對象的地址爲鍵值的記錄。
2. 將包含在記錄中的全部附有__weak修飾符變量的地址,賦值爲nil
3. 從weak表中刪除記錄
4. 從引用計數表中刪除廢棄對象的地址做爲鍵值的記錄
根據以上步驟,前面說的若是附有__weak修飾符的變量所引用的對象被廢棄,則將nil賦值給這個變量,這個功能即被實現。
__weak的第二個功能,使用__weak修飾符的變量,便是使用註冊到autoreleasepool中的對象。
{
id __weak obj_weak = obj;//obj已被賦值,而且是strong類型的
NSLog(@"%@",obj_weak);
}
/*編譯器的模擬代碼*/
id obj_weak;
objc_initweak(&obj_weak,obj);
id tmp = objc_loadWeakRetained(&obj_weak);
objc_autorelease(tmp);
NSLog(@"%@",tmp);
objc_destroyWeak(&obj_weak);
與被賦值時相比,在使用附有__weak修飾符變量的情形下,增長了對objc_loadWeakRetained函數和objc_autorelease函數的調用。這些函數的動做以下:
1. objc_loadWeakRetained函數取出附有__weak修飾符變量所引用的對象並retain
2. objc_autorelease函數將對象註冊到autorelease中。
由此可知,由於附有__weak修飾符變量所引用的對象這樣被註冊到autorelease中,因此在@autoreleasepool塊結束以前均可以放心使用。
注:OC中有一些類,並不支持ARC,例如NSMachPort類。能夠經過allowsWeakReference/retainWeakReference方法來判斷是否支持ARC
[※※※※※]可否向編譯後獲得的類中增長實例變量?可否向運行時建立的類中添加實例變量?爲何?
由於編譯後的類已經註冊在 runtime中,類結構體中的 objc_ivar_list實例變量的鏈表 和 instance_size 實例變量的內存大小已經肯定,同時runtime 會調用 class_setIvarLayout 或 class_setWeakIvarLayout 來處理 strong weak 引用。因此不能向存在的類中添加實例變量,
運行時建立的類是能夠添加實例變量,調用 class_addIvar函數。可是得在調用 objc_allocateClassPair以後,objc_registerClassPair以前,緣由同上。
[※※※]runloop和線程有什麼關係?
1. 每個線程中都一個runloop,只有主線的的runloop默認是開啓的,其餘線程的runloop是默認沒有開啓的
2. 能夠經過CFRunLoopRun()函數來開啓一個事件循環
3. 看SDWebImage源碼的時候見到有這麼用過.
[※※※]runloop的mode做用是什麼?
model 主要是用來指定時間在運行循環中的優先級的
蘋果公開提供的 Mode 有兩個:
kCFRunLoopDefaultMode
kCFRunLoopCommonModes
若是咱們把一個NSTimer對象以kCFRunLoopDefaultMode添加到主運行循環中的時候,當一直有用戶事件處理的時候,NSTimer將再也不被調度
若是咱們把一個NSTimer對象以kCFRunLoopCommonModes添加到主運行循環中的時候,當一直有用戶事件處理的時候,NSTimer還能正常的調度,互不影響.
[※※※※]以+ scheduledTimerWithTimeInterval...的方式觸發的timer,在滑動頁面上的列表時,timer會暫定回調,爲何?如何解決?
用sche建立的是在主線程是默認的模式下運行的,當滾動列表的時候runloop是運行在tracking的一個模式下,因此默認模式下的timer是不會執行,
解決,把timer加到common的一個模式下,這個是一個模式集合,包括默認的模式,和tracking的模式
若是咱們把一個NSTimer對象以kCFRunLoopDefaultMode添加到主運行循環中的時候,當一直有用戶事件處理的時候,NSTimer將再也不被調度
若是咱們把一個NSTimer對象以kCFRunLoopCommonModes添加到主運行循環中的時候,當一直有用戶事件處理的時候,NSTimer還能正常的調度,互不影響.
[※※※※※]猜測runloop內部是如何實現的?
1. 他是一個死循環
2.若是事件隊列中存放在事件,那就取出事件,執行相關代碼
3.若是沒有事件,就掛起,等有事件了,當即喚醒事件循環,開始執行.
簡單來講。。。
function loop() {
initialize();
do {
var message = get_next_message();
process_message(message);
} while (message != quit);
}
[※]objc使用什麼機制管理對象內存?
* MRC 手動引用計數 retainCount
* ARC 自動引用計數,如今一般使用自動引用計數 retainCount
[※※※※]ARC經過什麼方式幫助開發者管理內存?
經過編譯器在編譯的時候,插入如內管理的代碼動態的綁定
[※※※※]不手動指定autoreleasepool的前提下,一個autorealese對象在什麼時刻釋放?(好比在一個vc的viewDidLoad中建立)
在每次事件循環開始建立自動釋放池,在每次事件結束銷燬自動釋放池
以viewDidLoad方法爲例,能夠理解爲在viewDidLoad方法開始執行以前建立自動釋放池,
在viewDidLoad方法執行以後銷燬自動釋放池
[※※※※]BAD_ACCESS在什麼狀況下出現?
1. 死循環了
2. 訪問一個殭屍對象
[※※※※※]蘋果是如何實現autoreleasepool的?
1. 我猜測autoreleasepool本質就是一個隊列(數組),
2. 當調用autorelease的時候會把該對象添加到autoreleasepool中,而且把引用計數+1
3. 當autoreleasepool即將銷燬的時候,把其中的全部對象進行一次release操做
[※※]使用block時什麼狀況會發生引用循環,如何解決?
只要是一個對象對該block進行了強引用,在block內部有直接使用到該對象解決方案:在block外面使用__strong來修飾替換對應的強引用
[※※]在block內如何修改block外部變量?
經過 __bock修改的外部變量,能夠在block內部修改
當Block從棧複製到堆時,會使用_Block_object_assign函數持有該變量(至關於retain)。當堆上的Block被廢棄時,會使用_Block_object_dispose函數釋放該變量(至關於release)。
由上文描述可知,咱們可使用下述代碼解除Block循環引用的問題:
__block id tmp = self;
void(^block)(void) = ^{
tmp = nil;
};
block();
經過執行block方法,nil被賦值到_block變量tmp中。這個時候_block變量對 self 的強引用失效,從而避免循環引用的問題。使用__block變量的優勢是:
經過__block變量能夠控制對象的生命週期
在不能使用__weak修飾符的環境中,咱們能夠避免使用__unsafe_unretained修飾符
在執行Block時可動態地決定是否將nil或者其它對象賦值給__block變量
[※※※]使用系統的某些block api(如UIView的block版本寫動畫時),是否也考慮引用循環問題?
通常不用考慮,由於官方文檔中沒有告訴咱們要注意發生強引用,因此推測系統控件通常沒有對這些block進行強引用,因此咱們能夠不用考慮循環強引用的問題
[※※]GCD的隊列(dispatch_queue_t)分哪兩種類型?
並行隊列同時會開不少線程,(測試用了11個任務,結果顯示11個任務同時執行了),可使用信號量來控制線程數量,函數concurrentQueueTest中,最多同時運行三個任務;
串行隊列,執行完一個任務纔會執行下一個任務,若是有兩個串行隊列,則兩個串行隊列能夠併發執行,見serialQueueTest函數以及其輸出;
若是某些任務須要更另外一些任務完成後才執行,可使用dispatch_group_t,見groupQueueTest以及其輸出;
[※※※※]如何用GCD同步若干個異步調用?(如根據若干個url異步加載多張圖片,而後在都下載完成後合成一張整圖)
整體上說: 使用 dispatch group,而後 wait forever等待完成, 或者採起 group notify 來通知回調。
細節:
1. 建立異步隊列
2. 建立dispatch_group dispatch_group_t = dispatch_group_create()
3. 經過組來執行異步下載任務
dispatch_group_async(queueGroup, aQueue, ^{
NSLog(@"下載圖片.");
});
4.等到全部任務完成 dispatch_group_wait(queueGroup, DISPATCH_TIME_FOREVER);
5.合成圖片
[※※※※]dispatch_barrier_async的做用是什麼?
barrier:是障礙物的意思,在多個並行任務中間,他就像是一個隔離帶,把先後的並行任務分開.
dispatch_barrier_async 做用是在並行隊列中,等待前面操做並行任務完成再執行dispatch_barrier_async中的任務,若是後面還有並行任務,會開始執行後續的並行任務
[※※※※※]蘋果爲何要廢棄dispatch_get_current_queue?
容易誤用形成死鎖
[※※※※※]如下代碼運行結果如何?
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"1");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"2"); // 線程鎖死
});
NSLog(@"3");
}
只能輸出1,而後線程主線程死鎖
[※※]addObserver:forKeyPath:options:context:各個參數的做用分別是什麼,observer中須要實現哪一個方法才能得到KVO回調?
// 添加鍵值觀察
1. 調用對象:要監聽的對象
2. 參數
1> 觀察者,負責處理監聽事件的對象
2> 觀察的屬性
3> 觀察的選項
4> 上下文
[self.person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:@"Person Name"];
// NSObject 分類方法,意味着全部的 NSObject均可以實現這個方法!
// 跟協議的方法很像,分類方法又能夠稱爲「隱式代理」!不提倡用,可是要知道概念!
// 全部的 kvo監聽到事件,都會調用此方法
1. 觀察的屬性
2. 觀察的對象
3. change 屬性變化字典(新/舊)
4. 上下文,與監聽的時候傳遞的一致
能夠利用上下文區分不一樣的監聽!
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
NSLog(@"睡會 %@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:1.0];
NSLog(@"%@ %@ %@ %@", keyPath, object, change, context);
}
[※※※]如何手動觸發一個value的KVO
1.經過setValue:forKey:給屬性賦值
2.經過setValue:forKeyPath:給屬性賦值
3.直接調用setter方法方法給屬性賦值
4.直接經過指針給屬性賦值
給這個value設置一個值,就能夠觸發了
[※※※]若一個類有實例變量NSString *_foo,調用setValue:forKey:時,能夠以foo仍是_foo做爲key?
均可以
[※※※※]KVC的keyPath中的集合運算符如何使用?
1. 必須用在集合對象上或普通對象的集合屬性上
2. 簡單集合運算符有@avg, @count, @max , @min ,@sum,
3. 格式 @"@sum.age"或 @"集合屬性.@max.age"
[※※※※]KVC和KVO的keyPath必定是屬性麼?
1.一個能夠是成員變量
[※※※※※]如何關閉默認的KVO的默認實現,並進入自定義的KVO實現?
當你觀察一個對象時,一個新的類會動態被建立。這個類繼承自該對象的本來的類,並重寫了被觀察屬性的 setter方法。天然,重寫的 setter 方法會負責在調用原 setter 方法以前和以後,通知全部觀察對象值的更改。最後把這個對象的 isa指針 ( isa 指針告訴 Runtime系統這個對象的類是什麼 ) 指向這個新建立的子類,對象就神奇的變成了新建立的子類的實例。
原來,這個中間類,繼承自本來的那個類。不只如此,Apple還重寫了 -class 方法,企圖欺騙咱們這個類沒有變,就是本來那個類。更具體的信息,去跑一下 Mike Ash的那篇文章裏的代碼就能明白,這裏就再也不重複。
[※※※※※]apple用什麼方式實現對一個對象的KVO?
同上
[※※]IBOutlet連出來的視圖屬性爲何能夠被設置成weak?
由於視圖已經對它有一個強引用了
[※※※※※]IB中User Defined Runtime Attributes如何使用?
User Defined Runtime Attributes 是一個不被看重但功能很是強大的的特性,
它可以經過KVC的方式配置一些你在interface builder中不能配置的屬性。當你但願在IB中做盡量多得事情,
這個特性可以幫助你編寫更加輕量級的viewcontroller
[※※※]如何調試BAD_ACCESS錯誤
1.設置全局斷點快速定位問題代碼所在行
[※※※]lldb(gdb)經常使用的調試命令?
最經常使用就是 : po 對象
[※]淺拷貝深拷貝
淺拷貝是拷貝指針,深拷貝是新開闢空間,把裏面的類容拷貝出來
[※]#include,#import,@class的區別
#include
#include <> :用於對系統文件的引用,編譯器會在系統文件目錄下去查找該文件。
#include "xx.h":用於對用戶自定義的文件的引用,編譯器首先會去用戶目錄下查找,而後去安裝目錄,最後去系統目錄查找。
注:使用include要注意重複引用的問題:
class A,class B都引用了class C,class D若引用class A與class B,就會報重複引用的錯誤。
#import
功能與include基本相同,不過它避免了重複引用的問題。因此在OC中咱們基本用的都是import。
@class
@class就是告訴編譯器有這個類存在,可是類是如何實現的不用告訴編譯器.若.m文件用到了這個類,仍是要在.m文件彙總import這個類的。
既然這樣,爲何不直接在頭文件中import呢,舉個例子:
class A引用了class B,class B引用了class C.... , class A,B,C...的頭文件又import了不少文件,那麼 import了A的話,編譯器就須要編譯大量的文件,編譯時間就會增長。
難道頭文件中都是用@class嗎?固然不是,有時也是須要#import的,那麼何時該用什麼呢?
(1)通常若是有繼承關係的用#import,如B是A的子類那麼在B中聲明A時用#import;
(2) 另外就是若是有循環依賴關係,如:A->B,B->A這樣相互依賴時,若是在兩個文件的頭文件中用#import分別聲明對方,那麼就會出現頭文件循環利用的錯誤,這時在頭文件中用@class聲明就不會出錯;
(3)還有就是自定義代理的時候,若是在頭文件中想聲明代理的話如@interface SecondViewController:UIViewController時應用#import否則的話會出錯誤,注意XXXXDelegate是自定義的。
關鍵字const什麼含義
const意味着」只讀」,下面的聲明都是什麼意思?
const int a; a是常整型數
int const a; a是常整型數
const int *a; a是指向整型數的指針整型數不能夠修改,指針能夠修改
int * const a; 指針不可修改整型數能夠修改
int const * a const; 整型數不能夠修改 同時指針也不能夠修改
前兩個的做用是同樣,a是一個常整型數。第三個意味着a是一個指向常整型數的指針(也就是,整型數是不可修改的,但指針能夠)。第四個意思a是一個指向整型數的常指針(也就是說,指針指向的整型數是能夠修改的,但指針是不可修改的)。最後一個意味着a是一個指向常整型數的常指針(也就是說,指針指向的整型數是不可修改的,同時指針也是不可修改的)。
結論:
• 關鍵字const的做用是爲給讀你代碼的人傳達很是有用的信息,實際上,聲明一個參數爲常量是爲了告訴了用戶這個參數的應用目的。若是
你曾花不少時間清理其它人留下的垃圾,你就會很快學會感謝這點多餘的信息。(固然,懂得用const的程序員不多會留下的垃圾讓別人來清
理的。)
• 經過給優化器一些附加的信息,使用關鍵字const也許能產生更緊湊的代碼。
• 合理地使用關鍵字const可使編譯器很天然地保護那些不但願被改變的參數,防止其被無心的代碼修改。簡而言之,這樣能夠減小bug的出現。
欲阻止一個變量被改變,可使用 const 關鍵字。在定義該 const 變量時,一般須要對它進行初
始化,由於之後就沒有機會再去改變它了;
(2)對指針來講,能夠指定指針自己爲 const,也能夠指定指針所指的數據爲 const,或兩者同時指
定爲 const;
(3)在一個函數聲明中,const能夠修飾形參,代表它是一個輸入參數,在函數內部不能改變其值;
(4)對於類的成員函數,若指定其爲 const類型,則代表其是一個常函數,不能修改類的成員變量;
(5)對於類的成員函數,有時候必須指定其返回值爲 const類型,以使得其返回值不爲「左值」。
static做用?
(1) 函數體內 static變量的做用範圍爲該函數體,不一樣於 auto 變量,該變量的內存只被分配一次,所以其值在下次調用時仍維持上次的值;
(2)在模塊內的 static全局變量能夠被模塊內所用函數訪問,但不能被模塊外其它函數訪問;
(3)在模塊內的 static函數只可被這一模塊內的其它函數調用,這個函數的使用範圍被限制在聲明它的模塊內;
(4)在類中的 static成員變量屬於整個類所擁有,對類的全部對象只有一份拷貝;
(5)在類中的 static成員函數屬於整個類所擁有,這個函數不接收 this指針,於是只能訪問類的static 成員變量。
在類中聲明私有方法 ?
兩種方式:
1.不聲明方法只實現就能夠了
2.聲明在頭文件中,可是函數使用(private)修飾
堆和棧的區別?
管理方式:對於棧來說,是由編譯器自動管理,無需咱們手工控制;對於堆來講,釋放工做由程序員控制,容易產生memory leak。
申請大小:
棧:在Windows下,棧是向低地址擴展的數據結構,是一塊連續的內存的區域。這句話的意思是棧頂的地址和棧的最大容量是系統預先規定好的,在WINDOWS下,棧的大小是2M(也有的說是1M,總之是一個編譯時就肯定的常數),若是申請的空間超過棧的剩餘空間時,將提示overflow。所以,能從棧得到的空間較小。
堆:堆是向高地址擴展的數據結構,是不連續的內存區域。這是因爲系統是用鏈表來存儲的空閒內存地址的,天然是不連續的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限於計算機系統中有效的虛擬內存。因而可知,堆得到的空間比較靈活,也比較大。
碎片問題:對於堆來說,頻繁的new/delete勢必會形成內存空間的不連續,從而形成大量的碎片,使程序效率下降。對於棧來說,則不會存在這個問題,由於棧是先進後出的隊列,他們是如此的一一對應,以致於永遠都不可能有一個內存塊從棧中間彈出
分配方式:堆都是動態分配的,沒有靜態分配的堆。棧有2種分配方式:靜態分配和動態分配。靜態分配是編譯器完成的,好比局部變量的分配。動態分配由alloca函數進行分配,可是棧的動態分配和堆是不一樣的,他的動態分配是由編譯器進行釋放,無需咱們手工實現。
分配效率:棧是機器系統提供的數據結構,計算機會在底層對棧提供支持:分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執行,這就決定了棧的效率比較高。堆則是C/C++函數庫提供的,它的機制是很複雜的。
ViewController的didReceiveMemoryWarning是在何時調用的?默認的操做是什麼?
當程序接到內存警告時View Controller將會收到這個消息:didReceiveMemoryWarning
從iOS3.0開始,不須要重載這個函數,把釋放內存的代碼放到viewDidUnload中去。
這個函數的默認實現是:檢查controller是否能夠安全地釋放它的view(這裏加粗的view指的是controller的view屬性),好比view自己沒有superview而且能夠被很容易地重建(從nib或者loadView函數)。
若是view能夠被釋放,那麼這個函數釋放view並調用viewDidUnload。
你能夠重載這個函數來釋放controller中使用的其餘內存。但要記得調用這個函數的super實現來容許父類(通常是UIVIewController)釋放view。
若是你的ViewController保存着view的子view的引用,那麼,在早期的iOS版本中,你應該在這個函數中來釋放這些引用。而在iOS3.0或更高版本中,你應該在viewDidUnload中釋放這些引用。
怎麼理解MVC,在Cocoa中MVC是怎麼實現的?
MVC設計模式考慮三種對象:模型對象、視圖對象、和控制器對象。模型對象表明特別的知識和專業技能,它們負責保有應用程序的數據和定義操做數據的邏輯。視圖對象知道如何顯示應用程序的模型數據,並且可能容許用戶對其進行編輯。控制器對象是應用程序的視圖對象和模型對象之間的協調者。
ViewCotroller
Xib
delegate和notification區別,分別在什麼狀況下使用?
KVC(Key-Value-Coding)
KVO(Key-Value-Observing)
理解KVC與KVO(鍵-值-編碼與鍵-值-監看)
當經過KVC調用對象時,好比:[self valueForKey:@」someKey」]時,程序會自動試圖經過幾種不一樣的方式解析這個調用。首先查找對象是否帶有 someKey這個方法,若是沒找到,會繼續查找對象是否帶有someKey這個實例變量(iVar),若是尚未找到,程序會繼續試圖調用 -(id) valueForUndefinedKey:這個方法。若是這個方法仍是沒有被實現的話,程序會拋出一個NSUndefinedKeyException異常錯誤。
(Key-Value Coding查找方法的時候,不只僅會查找someKey這個方法,還會查找getsomeKey這個方法,前面加一個get,或者_someKey以及_getsomeKey這幾種形式。同時,查找實例變量的時候也會不只僅查找someKey這個變量,也會查找_someKey這個變量是否存在。)
設計valueForUndefinedKey:方法的主要目的是當你使用-(id)valueForKey方法從對象中請求值時,對象可以在錯誤發生前,有最後的機會響應這個請求。
類變量的@protected ,@private,@public,@package,聲明各有什麼含義?
上面的幾個聲明代表的是類成員的做用域,
@private做用範圍只能在自身類(外界既不可訪問,又不能繼承);
@protected做用範圍在自身類和子類,若是什麼都不加修飾,默認是@protected(外界不可訪問,可是能夠繼承);
@public做用範圍最大,能夠在任何地方被訪問(外界便可訪問,又能夠繼承);
@package做用範圍在某個框架內
線程是什麼?進程是什麼?兩者有什麼區別和聯繫?
(記住這個例子:進程能夠理解爲工廠的生產車間線程能夠理解爲工廠車間的生產線 一個工廠至少有一個生產車間 一個生產車間至少有一條生產線)
線程是CPU獨立運行和獨立調度的基本單位(能夠理解爲一個進程中執行的代碼片斷),
進程是資源分配的基本單位(進程是一塊包含了某些資源的內存區域)。
進程是線程的容器,真正完成代碼執行的是線程,而進程則做爲線程的執行環境。一個程序至少包含一個進程,一個進程至少包含一個線程,一個進程中的多個線程共享當前進程所擁有的資源。
談談你對多線程開發的理解?ios中有幾種實現多線程的方法?
好處:
一、使用線程能夠把程序中佔據時間長的任務放到後臺去處理,如圖片、視頻的下載(後臺執行IO流,加強體驗)
二、發揮多核處理器的優點,併發執行讓系統運行的更快、更流暢,用戶體驗更好(發揮優點,併發執行)
缺點:
一、大量的線程下降代碼的可讀性,
二、更多的線程須要更多的內存空間
三、當多個線程對同一個資源出現爭奪的時候要注意線程安全的問題。(這時候通常會使用線程鎖)
iOS有三種多線程編程的技術:
一、NSThread(兩種建立方式)
[NSThread detachNewThreadSelector:@selector(doSomething:) toTarget:self withObject:nil];
NSThread *myThread = [[NSThread alloc] initWithTarget:self selector:@selector(doSomething:) object:nil];
[myThread start];
二、NSOperationQueue
NSOperationQueue *oprationQueue = [[NSOperationQueue alloc] init];
oprationQueue addOperationWithBlock:^{
//這個block語句塊在子線程中執行
}
三、Grand Central Dispatch (GCD)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 耗時的操做好比下載應用程序 下載圖片上傳圖片
dispatch_async(dispatch_get_main_queue(), ^{
// 更新界面UI元素
}); });
http://blog.csdn.net/totogo2010/article/details/8016129
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL * url = [NSURL URLWithString:@"http://avatar.csdn.net/2/C/D/1_totogo2010.jpg"];
NSData * data = [[NSData alloc]initWithContentsOfURL:url];
UIImage *image = [[UIImage alloc]initWithData:data];
if (data != nil) {
dispatch_async(dispatch_get_main_queue(), ^{
self.imageView.image = image;
});
}
});
PS:不顯示的建立線程的方法:
用NSObject的類方法 performSelectorInBackground:withObject:建立一個線程:
[Obj performSelectorInBackground:@selector(doSomething) withObject:nil];
內存中的幾個區?
http://blog.csdn.net/hairetz/article/details/4141043
一個由C/C++編譯的程序佔用的內存分爲如下幾個部分
一、棧區(stack)—由編譯器自動分配釋放,存放函數的參數值,局部變量的值等。其操做方式相似於數據結構中的棧。
二、堆區(heap)通常由程序員分配釋放,若程序員不釋放,程序結束時可能由OS回收。注意它與數據結構中的堆是兩回事,分配方式卻是相似於鏈表,呵呵。(這就是爲何OC中的對象都是在堆區)
三、全局區(靜態區)(static)—,全局變量和靜態變量的存儲是放在一塊的,初始化的全局變量和靜態變量在一塊區域,未初始化的全局變量和未初始化的靜態變量在相鄰的另外一塊區域。-程序結束後由系統釋放。
四、文字常量區 —常量字符串就是放在這裏的。程序結束後由系統釋放
五、程序代碼區 —存放函數體的二進制代碼。
例子:
int a = 0; 全局初始化區
char *p1; 全局未初始化區
main() {
int b; 棧
char s[] = "abc"; 棧
char *p2; 棧
char *p3 = "123456"; 123456/0在常量區,p3在棧上。
static int c =0; 全局(靜態)初始化區
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
分配得來得10和20字節的區域就在堆區。
strcpy(p1, "123456"); 123456/0放在常量區,編譯器可能會將它與p3所指向的"123456"
優化成一個地方。
}
2、堆和棧的理論知識
2.1申請方式
stack(棧):由系統自動分配。例如,聲明在函數中一個局部變量int b;系統自動在棧中爲b開闢空間
heap(堆):須要程序員本身申請,並指明大小,在c中malloc函數
如p1 = (char *)malloc(10);
在C++中用new運算符
如p2 = new char[10];
可是注意p一、p2自己是在棧中的。
2.2申請後系統的響應
棧:只要棧的剩餘空間大於所申請空間,系統將爲程序提供內存,不然將報異常提示棧溢出。
堆:首先應該知道操做系統有一個記錄空閒內存地址的鏈表,當系統收到程序的申請時,會遍歷該鏈表,尋找第一個空間大於所申請空間的堆結點,而後將該結點從空閒結點鏈表
中刪除,並將該結點的空間分配給程序,另外,對於大多數系統,會在這塊內存空間中的首地址處記錄本次分配的大小,這樣,代碼中的delete語句才能正確的釋放本內存空間。
另外,因爲找到的堆結點的大小不必定正好等於申請的大小,系統會自動的將多餘的那部分從新放入空閒鏈表中。
2.3申請大小的限制
棧:在Windows下,棧是向低地址擴展的數據結構,是一塊連續的內存的區域。這句話的意思是棧頂的地址和棧的最大容量是系統預先規定好的,在WINDOWS下,棧的大小是2M(也有
的說是1M,總之是一個編譯時就肯定的常數),若是申請的空間超過棧的剩餘空間時,將提示overflow。所以,能從棧得到的空間較小。
堆:堆是向高地址擴展的數據結構,是不連續的內存區域。這是因爲系統是用鏈表來存儲的空閒內存地址的,天然是不連續的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限於計算機系統中有效的虛擬內存。因而可知,堆得到的空間比較靈活,也比較大。
2.4申請效率的比較:
棧由系統自動分配,速度較快。但程序員是沒法控制的。
堆是由new分配的內存,通常速度比較慢,並且容易產生內存碎片,不過用起來最方便.另外,在WINDOWS下,最好的方式是用VirtualAlloc分配內存,他不是在堆,也不是在棧是直接在進程的地址空間中保留一塊內存,雖然用起來最不方便。可是速度快,也最靈活。
2.5堆和棧中的存儲內容
棧:在函數調用時,第一個進棧的是主函數中後的下一條指令(函數調用語句的下一條可執行語句)的地址,而後是函數的各個參數,在大多數的C編譯器中,參數是由右往左入棧
的,而後是函數中的局部變量。注意靜態變量是不入棧的。當本次函數調用結束後,局部變量先出棧,而後是參數,最後棧頂指針指向最開始存的地址,也就是主函數中的下一條指令,程序由該點繼續運行。
堆:通常是在堆的頭部用一個字節存放堆的大小。堆中的具體內容由程序員安排。
2.6存取效率的比較
char s1[] = "aaaaaaaaaaaaaaa";
char *s2 = "bbbbbbbbbbbbbbbbb";
aaaaaaaaaaa是在運行時刻賦值的;
而bbbbbbbbbbb是在編譯時就肯定的;
可是,在之後的存取中,在棧上的數組比指針所指向的字符串(例如堆)快。
好比:
#include
void main()
{
char a = 1;
char c[] = "1234567890";
char *p ="1234567890";
a = c[1];
a = p[1];
return;
}
對應的彙編代碼
10: a = c[1];
00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh]
0040106A 88 4D FC mov byte ptr [ebp-4],cl
11: a = p[1];
0040106D 8B 55 EC mov edx,dword ptr [ebp-14h]
00401070 8A 42 01 mov al,byte ptr [edx+1]
00401073 88 45 FC mov byte ptr [ebp-4],al
第一種在讀取時直接就把字符串中的元素讀到寄存器cl中,而第二種則要先把指針值讀到
edx中,再根據edx讀取字符,顯然慢了。
2.7小結:
堆和棧的區別能夠用以下的比喻來看出:
使用棧就像咱們去飯館裏吃飯,只管點菜(發出申請),付錢,和吃(使用),吃飽了就走,沒必要理會切菜、洗菜等準備工做和洗碗、刷鍋等掃尾工做,他的好處是快捷,可是自由度小。
使用堆就象是本身動手作喜歡吃的菜餚,比較麻煩,可是比較符合本身的口味,並且自由度大。(經典!)
iOS的動態性
iOS的動態性來自三個方面:動態類型、動態綁定、動態載入、SEL類型
一、動態類型<弱類型>(id):在代碼的運行階段判斷代碼的類型,使用id類型可讓應用在「運行時」使用任何類型來替換。動態類型讓程序更加靈活,可是會使數據的統一性下降和代碼的可讀性。咱們經常使用靜態類型<強類型>(如NSString),使用靜態類型編譯器能夠徹底分析你的代碼,這讓代碼的性能和可預知性更高。
二、動態綁定:讓代碼在運行時判斷須要調用什麼方法,而不是在編譯時。動態類型和動態綁定使得選擇哪一個接收者已經調用什麼方法都放到運行時去完成。
三、動態載入:應用程序能夠根據須要加載可執行代碼以及資源,而不是在啓動時就加載全部資源。
四、SEL類型 iOS在編譯的時候會根據方法的名字(包括參數序列),生成一個用來區分這個方法的惟一的ID,這個ID是SEL類型的,SEL的本質就是類方法的編號[函數地址]。(相似C語言裏面的函數指針,可是OC的類不能直接使用函數指針,這樣只能作一個@selector語法來取。注意:@selector是查找當前類(含子類)的方法。)
怎樣實現一個singleton的類。
static LOSingleton * shareInstance;
+(LOSingleton *)sharedInstance
{
@synchronized(self){
//這個東西其實就是一個加鎖。若是self其餘線程訪問,則會阻塞。這樣作通常是用來對單例進行一個死鎖的保護
if (shareInstance == nil) {
shareInstance = [[super allocWithZone:NULL] init];
}
}
return shareInstance;
}
//第二種方式
+ (LOSingleton *) sharedInstance
{
static LOSingleton *sharedInstance = nil ;
static dispatch_once_t onceToken; // 鎖
dispatch_once (& onceToken, ^ { // 最多調用一次
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
什麼是安全釋放?
在對象release以後把指針置爲nil這樣保證了數據的清空和指針的清空;
什麼是序列化和反序列化,能夠用來作什麼?如何在OC中實現複雜對象的存儲?
若是你須要存儲一個複雜的對象的話,常常要以二進制的方法序列化這個對象,這個過程叫Archiving。若是一個對象須要進行序列化,那麼須要遵循NScoding協議,主要有兩個方法:
-(id)initWithCoder:(NSCoder*)coder;//從coder中讀取數據,保存到相應變量中,即反序列化數據。
-(void)encodeWithCoder:(NSCoder*)coder;//讀取實例變量,並把這些數據寫到coder中去,即序列化數據。
寫一個標準宏MIN,這個宏輸入兩個參數並返回較小的一個?
#define kMIN(X,Y) ((X) > (Y)) ? (Y) :(X)
#define kMIN(x,y) ((x) > (y)) ? (y) : (x)
描述應用程序的啓動順序。
一、程序入口main函數建立UIApplication實例和UIApplication代理實例.
二、在UIApplication代理實例中重寫啓動方法,設置第一ViewController.
三、在第一ViewController中添加控件,實現對應的程序界面.
讀取圖片
1.從資源(resource)讀取
UIImage* image=[UIImage imageNamed:@"1.jpg"];
2.從網絡讀取
NSURL *url=[NSURL URLWithString:@"http://www.sinaimg.cn/qc/photo_auto/chezhan/2012/50/00/15/80046_950.jpg"];
UIImage *imgFromUrl =[[UIImage alloc]initWithData:[NSData dataWithContentsOfURL:url]];
3.從手機本地讀取
//讀取本地圖片非resource
NSString *aPath3=[NSString stringWithFormat:@"%@/Documents/%@.jpg",NSHomeDirectory(),@"test"];
UIImage *imgFromUrl3=[[UIImage alloc]initWithContentsOfFile:aPath3];
UIImageView* imageView3=[[UIImageView alloc]initWithImage:imgFromUrl3];
4.從現有的context中得到圖像
//add ImageIO.framework and #import <ImageIO/ImageIO.h>
CGImageSourceRef source = CGImageSourceCreateWithURL((CFURLRef)url, NULL);
CGImageRef img= CGImageSourceCreateImageAtIndex(source,0,NULL);
CGContextRef ctx=UIGraphicsGetCurrentContext();
CGContextSaveGState(ctx);
//transformCTM的2種方式
//CGContextConcatCTM(ctx, CGAffineTransformMakeScale(.2, -0.2));
//CGContextScaleCTM(ctx,1,-1);
//注意座標要反下,用ctx來做爲圖片源
CGImageRef capture=CGBitmapContextCreateImage(ctx);
CGContextDrawImage(ctx, CGRectMake(160, 0, 160, 230), [image CGImage]);
CGContextDrawImage(ctx, CGRectMake(160, 230, 160, 230), img);
CGImageRef capture2=CGBitmapContextCreateImage(ctx);
5.用Quartz的CGImageSourceRef來讀取圖片
CGImageSourceRef source = CGImageSourceCreateWithURL((CFURLRef)url, NULL);
CGImageRef img= CGImageSourceCreateImageAtIndex(source,0,NULL);
二.保存圖片
1.轉換成NSData來保存圖片(imgFromUrl是UIImage)
//保存圖片 2種獲取路徑均可以
//NSArray*paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
//NSString*documentsDirectory=[paths objectAtIndex:0];
//NSString*aPath=[documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.jpg",@"test"]];
NSString *aPath=[NSString stringWithFormat:@"%@/Documents/%@.jpg",NSHomeDirectory(),@"test"];
NSData *imgData = UIImageJPEGRepresentation(imgFromUrl,0);
[imgData writeToFile:aPath atomically:YES];
2.用Quartz的CGImageDestinationRef來輸出圖片,這個方式不常見,因此不作介紹,詳細能夠看apple文檔Quartz 2D Programming Guide
三.繪製圖(draw|painting)
1.UIImageView方式加入到UIView層
UIImageView* imageView=[[UIImageView alloc]initWithImage:image];
imageView.frame=CGRectMake(0, 0, 320, 480);
[self addSubview:imageView];
[imageView release];
2.[img drawAtPoint]系列方法
[image4 drawAtPoint:CGPointMake(100, 0)];
3.CGContextDrawImage
CGContextDrawImage(ctx, CGRectMake(160, 0, 160, 230), [image CGImage]);
4.CGLayer
這個是apple推薦的一種offscreen的繪製方法,相比bitmapContext更好,由於它彷佛會利用iphone硬件(drawing-card)加速
CGLayerRef cg=CGLayerCreateWithContext(ctx, CGSizeMake(320, 480), NULL);
//須要將CGLayerContext來做爲緩存context,這個是必須的
CGContextRef layerContext=CGLayerGetContext(cg);
CGContextDrawImage(layerContext, CGRectMake(160, 230, 160, 230), img);
CGContextDrawLayerAtPoint(ctx, CGPointMake(0, 0), cg);
5.CALayer的contents
UIImage* image=[UIImage imageNamed:@"1.jpg"];
CALayer *ly=[CALayer layer];
ly.frame=CGRectMake(0, 0, 320, 460);
ly.contents=[image CGImage];
[self.layer addSublayer:ly];
四.其它
1.CGImage和UIImage互換
這樣就能夠隨時切換UIKit和Quartz之間類型,而且選擇您熟悉的方式來處理圖片.
CGImage cgImage=[uiImage CGImage];
UIImage* uiImage=[UIImage imageWithCGImage:cgImage];
2.UIImage resizableImageWithCapInsets的問題
假設一張44x29的圖片,一樣的Insets=UIEdgeInsetsMake(10,10,10,10)在@2x狀況和非@2x狀況下,表現會有不一樣,非@2x是OK正常的,可是若是一樣尺寸的圖片變成@2x,則致使在切換過渡的時候會很卡,應該是在不一樣的重繪致使的,表面緣由是由於Insets設置的是點,在@2x狀況下拉伸,其實拉昇的像素是上面20,下面也是20,可是圖片其實只有29,因此致使不正確,只要將insets設置成=UIEdgeInsetsMake(5,10,5,10)就正常了,因此之後要注意了。
3.動畫圖片使用注意
animationImage 設置完畢之後要startAnimation.不會自動啓動動畫圖片。
此外在讀取大量動畫圖片的時候不太適合用這個方法,由於一會兒那麼多圖片容易爆掉。能夠用這個方法替代,具體我也沒試,方法就是手動切換圖片,並不是直接使用系統方法而已。
imgV=[[UIImageView alloc]initWithFrame:CGRectMake(40, 40, 128, 128)];
[self.window addSubview:imgV];
[self performSelectorInBackground:@selector(playAnim)withObject:nil];
[imgV release];
-(void)playAnim{
for (int i=0;i<101;){
usleep(100000);
UIImage *image=[[UIImage alloc]initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%d",i+1 ] ofType:@"tiff"]];
[self performSelectorOnMainThread:@selector(changeImage:) withObject:image waitUntilDone:YES];
i++;
}
}
-(void)changeImage:(UIImage*)image{
imgV.image=image;
}
相關帖子:http://www.cocoachina.com/bbs/read.php?tid=110154
4.UIControl設置UIImage
問題描述主要是有一個很小的叉按鈕,須要響應很大的點擊區域,這個其實很簡單,代碼以下:
UIImage *bg=[UIImage imageNamed:@"heizi1.jpg"];
//圖片大於點及區域,縮小下就行
bg=[self scaleImage:bg ToSize:(CGSize){100,100}];
UIButton* button = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, 200, 200)];
//圖片大於button,則會被拉伸,若是小於button則居中顯示
[button setImage:bg forState:UIControlStateNormal];
此外多說一句,這個icon圖片若是要準備2套圖,縮放畢竟消耗效率
縮放圖片代碼
-(UIImage *)scaleImage:(UIImage *)img ToSize:(CGSize)itemSize{
UIImage *i;
CGSize itemSize=CGSizeMake(30, 30);
UIGraphicsBeginImageContext(itemSize);
CGRect imageRect=CGRectMake(0, 0, itemSize.width, itemSize.height);
[img drawInRect:imageRect];
i=UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return i;
從view截圖出來
#import <QuartzCore/QuartzCore.h>
-(UIImage *)getImageFromView:(UIView *)orgView{
UIGraphicsBeginImageContext(orgView.bounds.size);
[orgView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
http://blog.csdn.net/jerryvon/article/details/7526147#
用obj-c寫一個冒泡排序
NSMutableArray *arr = [NSMutableArray arrayWithArray:@[@"10",@"1",@"3",@"6",@"12",@"0",@"4",@"8"]];
NSString *temp;
for (int i = 0; i < arr.count; i++) {
for (int j = 0; j < arr.count - 1 - i; j++) {
if ([arr[j] integerValue] > [arr[j+1] integerValue]) {
temp = arr[j];
[arr replaceObjectAtIndex:j withObject:arr[j+1]];
[arr replaceObjectAtIndex:j+1 withObject:temp];
}
}
}
c語言寫一個冒泡排序
void bubblesort(int r[100],int n) {
for (int i = 0;i < n-1;i++){
for (int j = 0;j< n-1-j;j++){
if (r[j] > r[j+1]){
int temp = r[j];
r[j] = r[j+1];
r[j+1] = temp;
}
}
}
}
簡述你對UIView、UIWindow和CALayer的理解
UIView繼承於UIResponder, UIResponder繼承於NSObject,UIView能夠響應用戶事件。CALayer繼承於NSObject,因此CALayer不能響應事件。
UIView構建界面,UIView側重於對內容的管理,CALayer側重於對內容的繪製。
UIView是用來顯示內容的,能夠處理用戶事件;CALayer是用來繪製內容的,對內容進行動畫處理,依賴與UIView來進行顯示,不能處理用戶事件。
分析json、xml的區別?json、xml解析方式的底層是如何處理的?
json底層原理遍歷字符串中的字符,最終根據規定的特助字符,好比 {}, [], :號等進行區分,{}是字典,[]表示的時數組,:號是字典的鍵和值的分水嶺,最老是將json數據轉化爲字典。Xml兩種解析方式,DOM和SAX,DOM須要讀入整個XML文檔(文檔驅動),SAX是事件驅動的,並不須要讀入整個文檔,文檔的讀入過程也就是SAX的解析過程。
面向對象的三大特徵,並做簡單的介紹
封裝、繼承、多態。
封裝:是把客觀事物封裝成抽象的類,隱藏內部的實現,對外部提供接口。
繼承:可使用現有類的全部功能,而且在無需從新編寫原來的類的狀況下對這些功能進行擴展。好比:咱們通常繼承UIViewController來擴展咱們本身的控制器類
多態:不一樣的對象以本身的方式響應相同的的消息的能力叫作多態,或者說父類指針指向子類對象<如UITableView的,cellForRow方法,返回值類型是UITbaleViewCell,可是你返回的cell能夠是你自定義的cell,在好比多個類裏面都有同一個方法>
簡述NotificationCenter、KVC、KVO、Delegate?並說明它們之間的區別?
Notification:觀察者模式,controller向defaultNotificationCenter添加本身的 notification,其餘類註冊這個notification就能夠收到通知,這些類能夠在收到通知時作本身的操做(多觀察者默認隨機順序發通知給觀察者們,並且每一個觀察者都要等當前的某個觀察者的操做作完才能輪到他來操做,能夠用NotificationQueue的方式安排觀察者的反應順序,也能夠在添加觀察者中設定反映時間,取消觀察須要在viewDidUnload跟dealloc中都要註銷)。
KVC:鍵值編碼,能夠直接經過字符串的名字(key)來間接訪問屬性的機制,而不是經過調用getter和setter方法訪問。
KVO:觀測指定對象的屬性,當指定對象的屬性更改以後會通知相應的觀察者。
delegate:一對一,delegate遵循某個協議並實現協議聲明的方法。
分別描述類別(categories)和延展(extensions)是什麼?以及二者的區別?繼承和類別在實現中有何區別?爲何Category只能爲對象添加方法,卻不能添加成員變量?
category類目:在不知道源碼的狀況下爲一個類擴展方法,extension:爲一個類聲明私有方法和變量。
繼承是建立了一個新的類,而類別只是對類的一個擴展,仍是以前的類。
categories類目的做用就是爲已知的類添加方法。
說說響應鏈
當事件發生的時候,響應鏈首先被髮送給第一個響應者(每每是事件發生的視圖,也就是用戶觸摸屏幕的地方)。事件將沿着響應者鏈一直向下傳遞,直到被接受並做出處理。通常來講,第一響應這是個視圖對象或者其子類,當其被觸摸後事件就交由它處理,若是他不處理,事件就會被傳遞給視圖控制器對象UIViewController(若是存在),而後是它的父視圖對象(superview),以此類推直到頂層視圖。接下來會沿着頂層視圖(top view)到窗口(UIwindow 對象) 再到程序的(UIApplication對象),若是整個過程都沒有響應這個事件,則該事件被丟棄,通常狀況下,在響應鏈中只要有對象處理事件,事件就會被傳遞.典型的響應路線圖如:First Responser --> The Window -->The Applicationn --> App Delegate
你作iphone開發時候,有哪些傳值方式,view和Controller之間是如何傳值的?
屬性、delegate、blocks單例 通知 本地化userDefault splite數據庫 nskeyarcher
介紹一下XMPP?有什麼優缺點嗎?
XMPP:基於XML的點對點的即時通信協議。
XMPP 協議是公開的,XMPP協議具備良好的擴展性,安全性
缺點是隻能傳輸文本
http://blog.csdn.net/kaitiren/article/details/29586565
描述上拉加載、下拉刷新的實現機制?
根據下拉或者上拉的距離來判斷是否進行網絡請求,網絡請求的下拉刷新的時候要把對應的page值置爲0也就是第一頁 下拉刷新的時候要把對應的page++請求新一頁面的數據,而後針對現有的數組中添加數據這時候通常使用懶加載的形式添加對應可變數組
談談對性能優化的見解,如何作?
從用戶體驗出發:
一、程序logging不要太長、
二、相同數據不作重複獲取
三、昂貴資源要重用(cell、sqlite、date),
四、良好的編程習慣和程序設計:選擇正確的集合對象和算法來進行編程、選擇適合的數據存儲格式(plist、SQLite)、優化SQLite查詢語句
五、數據資源方面的優化(緩存和異步加載)
解決方案:
改進代碼和設計
可以發現問題
利用log或工具分析問題緣由
假設問題緣由
block的聲明和實現
聲明:
#import <Foundation/Foundation.h>
typedef void(^TestBlock)(NSString *string);
@interface LO_Person : NSObject
+ (void)showStringFromBlcok:(TestBlock)justBlock;
@end
實現:
#import "LO_Person.h"
@implementation LO_Person
+ (void)showStringFromBlcok:(TestBlock)justBlock
{
NSString *str = @"測試blcok";
justBlock(str);
}
@end
調用:
[LO_Person showStringFromBlcok:^(NSString *string) {
NSLog(@"-- %@",string);
}];
當前有一個數組,裏面有若干重複的數據,如何去除重複的數據?(會幾個寫幾個)
最簡單的方式,把數組裏面的元素放到集合裏面。
也能夠對數組進行排序,排序以後把數組裏相同的元素刪除掉
還可使用數組中的同一個數據即做爲key和value以後使用allValues來處理獲得不重複的數組
以.mm爲拓展名的文件裏,能夠包含的代碼有哪些?c和obj-c如何混用
obj-c的編譯器處理後綴爲m的文件時,能夠識別爲obj-c和c的代碼,處理mm文件能夠識別爲obj-c,c,c++代碼,但cpp文件必須只能用c/c++代碼,並且cpp文件include的頭文件中,也不能出現obj- c的代碼,由於cpp只是cpp
2) 在mm文件中混用cpp直接使用便可,因此obj-c混cpp不是問題
3)在cpp中混用obj- c其實就是使用obj-c編寫的模塊是咱們想要的。
若是模塊以類實現,那麼要按照cpp class的標準寫類的定義,頭文件中不能出現obj-c的東西,包括#import cocoa的。實現文件中,即類的實現代碼中可使用obj-c的東西,能夠import,只是後綴是mm。
若是模塊以函數實現,那麼頭文件要按 c的格式聲明函數,實現文件中,c++函數內部能夠用obj-c,但後綴仍是mm或m
在百度地圖的部分實現類中使用了C++的東西.
sizeof和strlen的區別和聯繫
sizeof是運算符,strlen是函數
char str[20] = "0123456789";
int a = strlen(str); //a=10; >>>> strlen 計算字符串的長度,以結束符 0x00 爲字符串結束。
int b = sizeof(str); //而b=20; >>>> sizeof計算的則是分配的數組 str[20]所佔的內存空間的大小,不受裏面存儲的內容改變。
sprintf,strcpy,memcpy的功能?使用上要有哪些要注意的地方?
char *strcpy(char *dest, const char *src);
其對字符串進行操做,完成從源字符串到目的字符串的拷貝,當源字符串的大小大於目的字符串的最大存儲空間後,執行該操做會出現段錯誤。
int sprintf(char*str, const char *format, ...)
函數操做的源對象不限於字符串:源對象能夠是字符串、也能夠是任意基本類型的數據。主要是實現將其餘數據類型轉換爲字符串
void *memcpy(void*dest, const void *src, size_t n)
實現內存的拷貝,實現將一塊內存拷貝到另外一塊內存。該函數對源對象與目的對象沒有類型如今,只是對內存的拷貝實現的內存的拷貝
什麼叫數據結構?
數據結構是計算機存儲、組織數據的方式。是指相互之間存在一種或多種特定關係的數據元素的集合。
一般,精心選擇的數據結構能夠帶來更高的運行或者存儲效率。
如何引用一個已經定義過的全局變量?
extern 能夠用引用頭文件的方式,也能夠用extern關鍵字,若是用引用頭文件的方式來引用某個在頭文件中的全局變量,假定你那個變量寫錯了,那麼編譯期間會報錯,若是用extern方式引用時,假定你犯了一樣的錯誤,那麼在編譯期間不會報錯,而在鏈接期間報錯。
TCP/IP 創建鏈接的過程?
客戶端:來我家吃飯吧?
服務器:好的你家作的飯夠不夠呀?
客戶端:放心吧夠吃! 完成確認鏈接
在TCP/IP 協議中,TCP協議提供可靠的鏈接服務,採用三次握手創建鏈接;
第一次握手:創建鏈接時,客戶端發送鏈接請求到服務器,並進入SYN_SEND狀態,等待服務器確認; (客戶端發送請求等待服務器確認 客戶端進入SYN_SEND狀態相似於問:來我家吃飯吧?)
第二次握手:服務器收到客戶端鏈接請求,向客戶端發送容許鏈接應答,此時服務器進入SYN_RECV狀態;(服務器接收到以後發送容許的應答此時服務器進入等待接收SYN_RECV 相似於:好的你家作的飯夠不夠呀? )
第三次握手:客戶端收到服務器的容許鏈接應答,向服務器發送確認,客戶端和服務器進入通訊狀態,完成三次握手。(客戶端向服務器發送容許確認完成:相似於:放心吧夠吃!)
(所謂的三次握手,就是要有三次鏈接信息的發送、接收過程。TCP連的創建須要進行三次鏈接信息的發送、接收。)
什麼是UDP和TCP的區別是什麼?
TCP 的全稱是傳輸控制協議,這種協議能夠提供面向鏈接的、可靠的、點到點的通訊,具備順序性!
UDP 的全稱是用戶數據包協議。他能夠提供非鏈接的不可靠的點懂啊多點的通訊,是osi參考模型中一種無鏈接的傳輸層協議,提供面向事務的簡單的不可靠信息傳輸,_IETF RFC 768 是UDP 的正式規範;
選擇何種協議,看程序注重那個方面,可靠抑或快速。
關於block的內部探究?
http://blog.csdn.net/jasonblog/article/details/7756763
http://blog.devtang.com/blog/2013/07/28/a-look-inside-blocks/
struct Block_descriptor {
unsigned long int reserved;
unsigned long int size;
void (*copy)(void *dst, void *src);
void (*dispose)(void *);
};
struct Block_layout {
void *isa;
int flags;
int reserved;
void (*invoke)(void *, ...);
struct Block_descriptor *descriptor;
/* Imported variables. */
};
經過該圖,咱們能夠知道,一個 block 實例實際上由 6部分構成:
isa 指針,全部對象都有該指針,用於實現對象相關的功能。
flags,用於按 bit位表示一些 block 的附加信息,本文後面介紹 block copy的實現代碼能夠看到對該變量的使用。
reserved,保留變量。
invoke,函數指針,指向具體的 block實現的函數調用地址。
descriptor, 表示該 block 的附加描述信息,主要是 size大小,以及 copy 和 dispose 函數的指針。
variables,capture過來的變量,block 可以訪問它外部的局部變量,就是由於將這些變量(或變量的地址)複製到告終構體中。
廣告頁面的邏輯:
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface SXAdManager : NSObject
+ (BOOL)isShouldDisplayAd;
+ (UIImage *)getAdImage;
+ (void)loadLatestAdImage;
@end
/**
* 思路:首先在啓動的時候判斷是否本地有URL若是沒有,那麼就直接跳過同時啓動請求廣告頁面的請求,下載後保存成nsdata數據格式寫在本地,下次啓動加載本次緩存的圖片,同時在下載圖片成功的時候刪除本次緩存的圖片將新的圖片數據移動到當前的位置.
*/
#import "SXAdManager.h"
#import "SXNetworkTools.h"
// 當前圖片路徑
#define kCachedCurrentImage ([[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)objectAtIndex:0]stringByAppendingString:@"/adcurrent.png"])
// 新的圖片路徑
#define kCachedNewImage ([[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)objectAtIndex:0]stringByAppendingString:@"/adnew.png"])
@interface SXAdManager ()
+ (void)downloadImage:(NSString *)imageUrl;
@end
@implementation SXAdManager
+ (BOOL)isShouldDisplayAd
{
return ([[NSFileManager defaultManager]fileExistsAtPath:kCachedCurrentImage isDirectory:NULL] || [[NSFileManager defaultManager]fileExistsAtPath:kCachedNewImage isDirectory:NULL]);
}
+ (UIImage *)getAdImage
{
if ([[NSFileManager defaultManager]fileExistsAtPath:kCachedNewImage isDirectory:NULL]) {
[[NSFileManager defaultManager]removeItemAtPath:kCachedCurrentImage error:nil];
[[NSFileManager defaultManager]moveItemAtPath:kCachedNewImage toPath:kCachedCurrentImage error:nil];}
return [UIImage imageWithData:[NSData dataWithContentsOfFile:kCachedCurrentImage]];
}
+ (void)downloadImage:(NSString *)imageUrl
{
//異步下載圖片
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:[NSURL URLWithString:imageUrl]];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
NSURLSessionTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (data) {
[data writeToFile:kCachedNewImage atomically:YES];
}
}];
[task resume];
}
+ (void)loadLatestAdImage
{
NSInteger now = [[[NSDate alloc] init] timeIntervalSince1970]; // 獲取當前的時間
NSString *path = [NSString stringWithFormat:@"http://g1.163.com/madr?app=7A16FBB6&platform=ios&category=startup&location=1×tamp=%ld",(long)now];//請求參數
[[[SXNetworkTools sharedNetworkToolsWithoutBaseUrl]GET:path parameters:nil success:^(NSURLSessionDataTask *task, NSDictionary* responseObject) {
NSLog(@"responseObject == %@",responseObject);
NSArray *adArray = [responseObject valueForKey:@"ads"];
NSString *imgUrl = adArray[0][@"res_url"][0];
NSString *imgUrl2 = nil;
if (adArray.count >1) {
imgUrl2= adArray[1][@"res_url"][0];
}
BOOL one = [[NSUserDefaults standardUserDefaults]boolForKey:@"one"];
if (imgUrl2.length > 0) {
if (one) {
[self downloadImage:imgUrl];
[[NSUserDefaults standardUserDefaults]setBool:!one forKey:@"one"];
}else{
[self downloadImage:imgUrl2];
[[NSUserDefaults standardUserDefaults]setBool:!one forKey:@"one"];
}
}else{
[self downloadImage:imgUrl];
}
} failure:^(NSURLSessionDataTask *task, NSError *error) {
NSLog(@"%@",error);
}] resume];
}
@end
webView的默認緩存大小?
<ul>
<li>Memory capacity: 4 megabytes (4 * 1024 * 1024 bytes) 內存中默認是4M
<li>Disk capacity: 20 megabytes (20 * 1024 * 1024 bytes) 磁盤中20M
<li>Disk path: <nobr>(user home directory)/Library/Caches/(application bundle id)</nobr>
</ul>
#pragma mark - ******************** 拼接html語言
- (void)showInWebView
{
NSMutableString *html = [NSMutableString string];
[html appendString:@"<html>"];
[html appendString:@"<head>"];
[html appendFormat:@"<link rel=\"stylesheet\" href=\"%@\">",[[NSBundle mainBundle] URLForResource:@"SXDetails.css" withExtension:nil]];
[html appendString:@"</head>"];
[html appendString:@"<body>"];
[html appendString:[self touchBody]];
[html appendString:@"</body>"];
[html appendString:@"</html>"];
[self.webView loadHTMLString:html baseURL:nil];
}
- (NSString *)touchBody
{
NSMutableString *body = [NSMutableString string];
[body appendFormat:@"<div class=\"title\">%@</div>",self.detailModel.title];
[body appendFormat:@"<div class=\"time\">%@</div>",self.detailModel.ptime];
if (self.detailModel.body != nil) {
[body appendString:self.detailModel.body];
}
// 遍歷img
for (SXDetailImgModel *detailImgModel in self.detailModel.img) {
NSMutableString *imgHtml = [NSMutableString string];
// 設置img的div
[imgHtml appendString:@"<div class=\"img-parent\">"];
// 數組存放被切割的像素
NSArray *pixel = [detailImgModel.pixel componentsSeparatedByString:@"*"];
CGFloat width = [[pixel firstObject]floatValue];
CGFloat height = [[pixel lastObject]floatValue];
// 判斷是否超過最大寬度
CGFloat maxWidth = [UIScreen mainScreen].bounds.size.width * 0.96;
if (width > maxWidth) {
height = maxWidth / width * height;
width = maxWidth;
}
// 調用js
NSString *onload = @"this.onclick = function() {"
"window.location.href = 'sx:src=' +this.src;"
"};";
[imgHtml appendFormat:@"<img onload=\"%@\" width=\"%f\" height=\"%f\" src=\"%@\">",onload,width,height,detailImgModel.src];
// 結束標記
[imgHtml appendString:@"</div>"];
// 替換標記
[body replaceOccurrencesOfString:detailImgModel.ref withString:imgHtml options:NSCaseInsensitiveSearch range:NSMakeRange(0, body.length)];
}
return body;
}
#pragma mark -- UIWebViewDelegate
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
NSString *url = request.URL.absoluteString;
NSRange range = [url rangeOfString:@"sx:src="];
if (range.location != NSNotFound) {
NSInteger begin = range.location + range.length;
NSString *src = [url substringFromIndex:begin];
[self savePictureToAlbum:src];
return NO;
}
return YES;
}
KVO 的奧祕
KVO(key-value-observing)是一種十分有趣的回調機制,在某個對象註冊監聽者後,在被監聽的對象發生改變時,對象會發送一個通知給監聽者,以便監聽者執行回調操做。
KVO的使用很是簡單,使用KVO的要求是對象必須能支持kvc機制——全部NSObject的子類都支持這個機制。拿上面的漸變導航欄作??,咱們爲tableView添加了一個監聽者controller,在咱們滑動列表的時候,會計算當前列表的滾動偏移量,而後改變導航欄的背景色透明度。
Key-Value Observing (簡寫爲KVO):當指定的對象的屬性被修改了,容許對象接受到通知的機制。每次指定的被觀察對象的屬性被修改的時候,KVO都會自動的去通知相應的觀察者。
//添加監聽者
[self.tableView addObserver: self forKeyPath: @"contentOffset" options: NSKeyValueObservingOptionNew context: nil];
/**
* 監聽屬性值發生改變時回調
*/
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
CGFloat offset = self.tableView.contentOffset.y;
CGFloat delta = offset / 64.f + 1.f;
delta = MAX(0, delta);
[self alphaNavController].barAlpha = MIN(1, delta);
}
KVO的優勢:
當有屬性改變,KVO會提供自動的消息通知。這樣的架構有不少好處。
首先,開發人員不須要本身去實現這樣的方案:每次屬性改變了就發送消息通知。這是KVO機制提供的最大的優勢。由於這個方案已經被明肯定義,得到框架級支持,能夠方便地採用。開發人員不須要添加任何代碼,不須要設計本身的觀察者模型,直接能夠在工程裏使用。
其次,KVO的架構很是的強大,能夠很容易的支持多個觀察者觀察同一個屬性,以及相關的值。
KVO如何工做:
須要三個步驟來創建一個屬性的觀察員。理解這三個步驟就能夠知道KVO如何設計工做的。
(1)首先,構思一下以下實現KVO是否有必要。好比,一個對象,當另外一個對象的特定屬性改變的時候,須要被通知到。例如,PersonObject但願可以覺察到BankObject對象的accountBalance屬性的任何變化。
(2)那麼 PersonObject必須發送一個「addObserver:forKeyPath:options:context:」消息,註冊成爲 BankObject的accountBalance屬性的觀察者。(說明:「addObserver:forKeyPath:options:context:」方法在指定對象實例之間創建了一個鏈接。注意,這個鏈接不是兩個類之間創建的,而是兩個對象實例之間創建的。)
(3)爲了可以響應消息,觀察者必須實現 「observeValueForKeyPath:ofObject:change:context:」方法。這個方法實現如何響應變化的消息。在這個方法裏面咱們能夠跟本身的狀況,去實現應對被觀察對象屬性變更的相應邏輯。
(4)假如遵循KVO規則的話,當被觀察的屬性改變的話,方法 「observeValueForKeyPath:ofObject:change:context:」會自動被調用。
1. 你使用過Objective-C的運行時編程(Runtime Programming)麼?若是使用過,你用它作了什麼?你還能記得你所使用的相關的頭文件或者某些方法的名稱嗎?
Objecitve-C的重要特性是Runtime(運行時),在#import <objc/runtime.h>下能看到相關的方法,用過objc_getClass()和class_copyMethodList()獲取過私有API;
objective-c
Method method1 = class_getInstanceMethod(cls, sel1);
Method method2 = class_getInstanceMethod(cls, sel2);
method_exchangeImplementations(method1, method2);
代碼交換兩個方法,在寫unit test時使用到。
3. Core開頭的系列的內容。是否使用過CoreAnimation和CoreGraphics。UI框架和CA,CG框架的聯繫是什麼?分別用CA和CG作過些什麼動畫或者圖像上的內容。(有須要的話還能夠涉及Quartz的一些內容)
UI框架的底層有CoreAnimation,CoreAnimation的底層有CoreGraphics。
UIKit |
------------ |
Core Animation |
Core Graphics |
Graphics Hardware|
使用CA作過menu菜單的展開收起
4. 是否使用過CoreText或者CoreImage等?若是使用過,請談談你使用CoreText或者CoreImage的體驗。
CoreText能夠解決複雜文字內容排版問題。CoreImage能夠處理圖片,爲其添加各類效果。體驗是很強大,挺複雜的。
5. NSNotification和KVO的區別和用法是什麼?何時應該使用通知,何時應該使用KVO,它們的實現上有什麼區別嗎?若是用protocol和delegate(或者delegate的Array)來實現相似的功能可能嗎?若是可能,會有什麼潛在的問題?若是不能,爲何?
NSNotification是通知模式在iOS的實現,KVO的全稱是鍵值觀察(Key-value observing),其是基於KVC(key-value coding)的,KVC是一個經過屬性名訪問屬性變量的機制。例如將Module層的變化,通知到多個Controller對象時,可使用NSNotification;若是是隻須要觀察某個對象的某個屬性,可使用KVO。
delegate對於委託模式,在設計模式中是對象適配器模式,其是delegate是指向某個對象的,這是一對一的關係,而在通知模式中,每每是一對多的關係。委託模式,從技術上能夠如今改變delegate指向的對象,但不建議這樣作,會讓人迷惑,若是一個delegate對象不斷改變,指向不一樣的對象。
6. 你用過NSOperationQueue麼?若是用過或者瞭解的話,你爲何要使用NSOperationQueue,實現了什麼?請描述它和GCD的區別和相似的地方(提示:能夠從二者的實現機制和適用範圍來描述)。
使用NSOperationQueue用來管理子類化的NSOperation對象,控制其線程併發數目。GCD和NSOperation均可以實現對線程的管理,區別是 NSOperation和NSOperationQueue是多線程的面向對象抽象。項目中使用NSOperation的優勢是NSOperation是對線程的高度抽象,在項目中使用它,會使項目的程序結構更好,子類化NSOperation的設計思路,是具備面向對象的優勢(複用、封裝),使得實現是多線程支持,而接口簡單,建議在複雜項目中使用。
項目中使用GCD的優勢是GCD自己很是簡單、易用,對於不復雜的多線程操做,會節省代碼量,而Block參數的使用,會是代碼更爲易讀,建議在簡單項目中使用。
7. 既然提到GCD,那麼問一下在使用GCD以及block時要注意些什麼?它們兩是一回事兒麼?block在ARC中和傳統的MRC中的行爲和用法有沒有什麼區別,須要注意些什麼?如何避免循環引用?
使用block是要注意,若將block作函數參數時,須要把它放到最後,GCD是Grand Central Dispatch,是一個對線程開源類庫,而Block是閉包,是可以讀取其餘函數內部變量的函數。
未完待續...