字符串截取程序員
NSString *strSub = [str substringFormIndex:2];
算法
NSString *strSubT = [str substringToIndex:2];
編程
NSString *strSubR = [str substringWithRange:range];
json
字符串替換windows
NSString *newStr = [str stringByReplacingOccurencesOfString:@"ll" withString:@"al"];
設計模式
編碼,把UTF8編碼的字符串編碼成URL中可用的字符串
數組
url_cn = [url_cn stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
緩存
字符串轉數組安全
NSArray *array = [str componentsSeparatedByString:@","];--分隔符
bash
數組轉字符串
NSString *str = [array componentsJoinedByString:@","];--分隔符
字符串轉字典
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSError *err;
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData
options:NSJSONReadingMutableContainers
error:&err];複製代碼
字典轉字符串
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:&parseError];複製代碼
數組替換
[_dataSource replaceObjectAtIndex:1 withObject:recentArray];
數組倒序
NSArray *array = @[@1, @20, @3, @10, @2];//排序後到新數組裏
NSArray *sortedArray = [array sortedArrayUsingComparator:^NSComparisonResult(NSNumber* obj1, NSNumber* obj2) {
if ([obj1 intValue] > [obj2 intValue]) {
return NSOrderedDescending;
} else {
return NSOrderedAscending;
}
}];複製代碼
1》performSelector方法
- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay;複製代碼
2》NSTimer定時器
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;複製代碼
3》NSThread線程的sleep
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;複製代碼
4》GCD
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
});複製代碼
//建立
@protocol MyDelegate
@required
-(void)eat:(NSString *)food;
@optional
-(void)run;
@end
//聲明.h
@interface person:NSObject<MyDelegate>
@end
//實現.m
@implementation person
-(void)eat:(NSString *)food{
}
-(void)run{
}
@end複製代碼
這種問題在開發時常常遇到,緣由是訪問了野指針,好比訪問已經釋放的對象的成員變量或者發消息、死循環等。
1》p 輸出基本類型,是打印命令,須要指定類型,是print的簡寫
p (int)[[[self view] subviews] count]複製代碼
2》po 打印對象,會調用description方法,是print-object的簡寫
po [self view]複製代碼
3》expr 能夠在調試時動態執行制定表達式,並將結果打印出來。經常使用於在調試過程當中修改變量的值。
4》bt 打印調用堆棧,是thread backtrace的簡寫,加all可打印全部的thread的堆棧
5》br l 是breakpoint list的簡寫
Instruments裏面工具不少,經常使用的有:
1》Time Profiler:性能分析
2》Zoombies:檢查是否訪問了殭屍對象,可是這個工具只能從上往下檢查,不智能
3》Allocations:用來檢查內存,寫算法的那批人也用這個來檢查
4》Leaks:檢查內存,看是否有內存泄漏
數據存儲有四種方案:NSUserDefault、KeyChain、file、DB。
其中File有三種方式:plist、Archive(歸檔)
DB包括:SQLite、FMDB、CoreData複製代碼
1》獲取類裏面的全部成員變量
2》爲類動態添加成員變量
3》動態改變類的方法實現
4》爲類動態添加新的方法。
相比於UIWebView的優點
1》在性能、穩定性、佔用內存方面有很大提高
2》容許JavaScript的Nitro庫加載並使用(UIWebView中限制)
3》增長加載進度實行:estimatedProgress,不用再本身寫進度條了
4》支持了更多的HTML屬性。
1》base64加密:基本原理是本來是8個bit一組表示數據,改成6個bit一組表示數據,不足的部分補零,每兩個0用一個 = 表示;用base64編碼以後,數據長度會變大,增長了大約1/3左右;可進行反向解密;編碼有個很是顯著的特色,末尾有個 = 號
2》MD5加密:把任意一個長度的字符串換成必定長度的十六進制的大整數
3》AES加密
4》RSA加密
1》咱們只能在繼承了UIView的子類中經過重寫drawRect方法來繪製圖形
2》若是須要繪製圖形的子類直接繼承自UIView,則子類的drawRect中不須要調用父類方法[super drawRect:rect];
。若是子類繼承自其它繼承UIView的view類,則drawRect方法中須要調用父類方法[super drawRect:rect];
。
3》drawRect方法不能手動直接調用,咱們能夠經過調用其它方法來實現drawRect方法的調用。如:在子類初始化時調用- (instancetype)initWithFrame:(CGRect)frame
方法,且frame不爲CGRectZero時。
4》咱們能夠調用setNeedsDisplay()
方法或setNeedsDisplayInRect
方法,可是該方法不會本身調用drawRect方法,而是會標記視圖,並在下一次循環更新的時候讓視圖經過drawRect來進行重繪,前提是rect不爲CGRectZero。
1》臨界區:指的是一塊對公共資源進行訪問的代碼,並不是是一種機制或者算法。
2》互斥鎖:是一種用於多線程編程中,防止兩條線程同時對同一個公共資源進行讀寫的機制,該目的經過將代碼切片成一個一個的臨界區而達成。
3》自旋鎖:是用於多線程同步的一種鎖,線程會反覆檢查鎖變量是否可用。因爲線程在這一過程當中保持執行,所以是一種忙等待。一旦獲取了自旋鎖,線程會一直保持該鎖,直至顯示釋放自旋鎖。自旋鎖避免了進城上下文的調度開銷,所以對於線程只會阻塞很短期的場合是有效的。
4》讀寫鎖:是計算機程序的併發控制的一種同步機制,也稱「共享-互斥鎖」、多讀者-單寫者鎖,用於解決多線程對公共資源的讀寫問題。讀操做可併發重入,寫操做是互斥的。讀寫鎖一般用互斥鎖、條件變量、信號量實現。
5》信號量:是一種更高級的同步機制,互斥鎖能夠說是semaphore在僅取值0/1的特例。信號量能夠有更多的取值空間,用來實現更加複雜的同步,而不僅僅是線程間互斥。
6》條件鎖:就是條件變量,當進城的某些資源要求不知足時就進入休眠,也就是鎖住了。當資源被分配到了,條件鎖打開,進城繼續運行。
無論是集合類對象(NSArray、NSDictionary、NSSet ... 之類的對象),仍是非集合類對象(NSString, NSNumber ... 之類的對象),接收到copy和mutableCopy消息時,都遵循如下準則:
1. copy 返回的是不可變對象(immutableObject);若是用copy返回值調用mutable對象的方法就會crash。
2. mutableCopy 返回的是可變對象(mutableObject)。
1、非集合類對象的copy與mutableCopy
在非集合類對象中,對不可變對象進行copy操做,是指針複製,mutableCopy操做是內容複製;
對可變對象進行copy和mutableCopy都是內容複製。用代碼簡單表示以下:
NSString *str = @"hello word!";
NSString *strCopy = [str copy] // 指針複製,strCopy與str的地址同樣
NSMutableString *strMCopy = [str mutableCopy] // 內容複製,strMCopy與str的地址不同
NSMutableString *mutableStr = [NSMutableString stringWithString: @"hello word!"];
NSString *strCopy = [mutableStr copy] // 內容複製
NSMutableString *strMCopy = [mutableStr mutableCopy] // 內容複製
2、集合類對象的copy與mutableCopy (同上)
在集合類對象中,對不可變對象進行copy操做,是指針複製,mutableCopy操做是內容複製;
對可變對象進行copy和mutableCopy都是內容複製。可是:集合對象的內容複製僅限於對象自己,對集合內的對象元素仍然是指針複製。(即單層內容複製)
NSArray *arr = @[@[@"a", @"b"], @[@"c", @"d"];
NSArray *copyArr = [arr copy]; // 指針複製
NSMutableArray *mCopyArr = [arr mutableCopy]; //單層內容複製
NSMutableArray *array = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil];
NSArray *copyArr = [mutableArr copy]; // 單層內容複製
NSMutableArray *mCopyArr = [mutableArr mutableCopy]; // 單層內容複製
【總結一句話】:
只有對不可變對象進行copy操做是指針複製(淺複製),其它狀況都是內容複製(深複製)!複製代碼
答:
// retain
- (void)setName:(NSString *)str {
[str retain];
[_name release];
_name = str;
}
// copy
- (void)setName:(NSString *)str {
id t = [str copy];
[_name release];
_name = t;
}複製代碼
當一個對象調用setValue方法時,方法內部會作如下操做:
1). 檢查是否存在相應的key的set方法,若是存在,就調用set方法。
2). 若是set方法不存在,就會查找與key相同名稱而且帶下劃線的成員變量,若是有,則直接給成員變量屬性賦值。
3). 若是沒有找到_key,就會查找相同名稱的屬性key,若是有就直接賦值。
4). 若是尚未找到,則調用valueForUndefinedKey:和setValue:forUndefinedKey:方法。
這些方法的默認實現都是拋出異常,咱們能夠根據須要重寫它們。複製代碼
1). class反射
經過類名的字符串形式實例化對象。
Class class = NSClassFromString(@"student");
Student *stu = [[class alloc] init];
將類名變爲字符串。
Class class =[Student class];
NSString *className = NSStringFromClass(class);
2). SEL的反射
經過方法的字符串形式實例化方法。
SEL selector = NSSelectorFromString(@"setName");
[stu performSelector:selector withObject:@"Mike"];
將方法變成字符串。
NSStringFromSelector(@selector*(setName:));複製代碼
1). 直接經過方法名來調用。[person show];
2). 間接的經過SEL數據來調用 SEL aaa = @selector(show); [person performSelector:aaa]; 複製代碼
沙盒結構:
1). Application:存放程序源文件,上架前通過數字簽名,上架後不可修改。
2). Documents:經常使用目錄,iCloud備份目錄,存放數據。(這裏不能存緩存文件,不然上架不被經過)
3). Library:
Caches:存放體積大又不須要備份的數據。(經常使用的緩存路徑)
Preference:設置目錄,iCloud會備份設置信息。
4). tmp:存放臨時文件,不會被備份,並且這個文件下的數據有可能隨時被清除的可能。複製代碼
TCP:傳輸控制協議。
UDP:用戶數據協議。
TCP 是面向鏈接的,創建鏈接須要經歷三次握手,是可靠的傳輸層協議。
UDP 是面向無鏈接的,數據傳輸是不可靠的,它只管發,無論收不收穫得。
簡單的說,TCP注重數據安全,而UDP數據傳輸快點,但安全性通常。複製代碼
OSI採用了分層的結構化技術,共分七層:
物理層、數據鏈路層、網絡層、傳輸層、會話層、表示層、應用層。複製代碼
block本質上是一個OC對象,他內部也有一個isa指針。block是封裝了函數調用以及函數調用環境的OC對象。
一共有三種block,分別是全局的、棧上的、堆上的
__NSGlobalBlock__直到程序結束纔會被回收
__NSStackBlock__類型block存放在棧中,咱們直到棧中的內存由系統自動分配和釋放,做用域執行完畢以後就會被當即釋放
__NSMallocBlock__是在平時編碼過程當中最經常使用到的。存放在堆中須要咱們本身進行內存管理。
__block
用於解決block內部不能修改auto變量值的問題,__block
不能修飾靜態變量(static) 和全局變量
方法一:
a = a + b;
b = a - b; // b = (a +b)-b,即 b = a
a = a - b; // a = (a+b)-a
方法二:
a = a - b;
b = a + b; // b = (a-b)+b,即b=a
a = b - a; // a = a - (a-b)複製代碼
1》觀察者模式:KVO是典型的觀察者模式,觀察某個屬性的改變,改變時會通知觀察者
2》委託模式:代理+協議的組合,實現1對1的反向傳值操做
3》單利模式:經過static關鍵詞,聲明全局變量,在整個進程運行期間只會被賦值一次
1》@property的本質是實例變量+存取方法。
2》原子性與非原子性
讀寫權限
內存管理語義 assign strong weak copy
方法名 getter setter
不經常使用的 nonnull nullable等
1》在ARC中,有可能出現循環引用的時候使用weak,好比代理,block;自身已經對他進行一次強引用,沒有必要再強引用一次,好比IBOutlot,由於父控件的subviews數組已經對他有一個強引用
2》weak代表該屬性定義了一種「非擁有關係」。在該屬性所指的對象銷燬時,屬性值會自動清空(nil)。
3》assign能夠用於非OC對象,weak必須用於OC對象。
1》NSString,NSArray,NSDictionary等常用copy關鍵字,由於他們有對應的可變類型。若是使用strong關鍵字,那麼這個屬性就有可能指向一個可變對象,若是這個可變對象修改了,那麼會影響該屬性。若是可變對象使用了copy關鍵字,那麼這個可變對象作增刪改的時候,系統會由於找不到對應的程序而崩潰。由於copy複製的是一個不可變對象,不可變對象是不能進行增刪改的操做的。
2》block也常用copy關鍵字。block使用copy關鍵字是從MRC留下來的傳統,方法內部的block是在棧區的,使用copy能夠把他放到堆區。在ARC中寫不寫都行,使用copy或者strong效果都是同樣的。
1》該類須要聽從NSCopying協議
2》實現NSCopying的協議: - (id)copyWithZone:(NSZone *)zone;
若是@synthesize和@dynamic都沒寫,那麼默認的就是@synthesize var = _var ;@synthesize的語義是若是你沒有手動實現setter和getter方法,那麼編譯器會自動爲你加上這兩個方法。@dynamic告訴編譯器,屬性的setter和getter方法油用戶本身實現,不自動生成。
OC的數據類型有NSString,NSArray,NSData等等,這些都是class,建立後即是對象,而C語言的基本數據類型是int,只是有必定字節的內存空間,用於存放數值。NSinteger是基本數據類型,不是NSNumber的子類,固然也不是NSObject的子類。NSInteger是基本數據類型int或者long的別名。他的區別在於,NSInteger會根據系統是32位仍是64位來決定自己是int仍是long。
OC的內存管理模式主要有三種:ARC(自動內存計數)、手動內存計數、內存池
1》自動內存計數(ARC):由Xcode自動在APP編譯階段,在代碼中添加內存管理代碼
2》手動內存計數(MRC):遵循內存誰申請,誰釋放;誰添加,誰釋放的原則
3》內存釋放池:把須要釋放的內存統一放在一個池子裏面,當池子被抽乾後,池子中全部的內存空間也會被自動釋放。內存池的釋放操做分爲自動和手動,自動釋放受runloop機制影響。
1》strong指針可以保持對象的生命,一個對象只要有strong指針指向他,那麼他就不會被釋放,相反的,若是沒有strong指針指向他,那麼他就會被自動釋放。默認的局部變量都是強指針,存放在堆裏面
2》weak型的指針變量仍然能夠是一個對象,可是不屬於對象的擁有者。即當對象被銷燬的時候,這個weak指針也就自動指向nil。
如何判斷當前文件是MRC仍是ARC:dealloc方法中可否調用super,只有MRC才能調用super;可否用retain、release,若是能夠就是MRC。
MRC沒有strong、weak,局部變量對象就是至關於基本數據類型;MRC給成員變量賦值必定要用set方法,不能直接訪問下劃線成員屬性賦值。
總之,只要block不引用外部變量,block放在全局區。
MRC 管理block:只要block引用外部變量,block放在棧區,block只能使用copy不能使用retain,用retain,block仍是在棧裏面
ARC管理block:只要block引用外部變量,block就放在堆區,block使用copy,儘可能不要使用strong。
1》KVO是觀察者模式,通常搭配KVC使用,經過KVO能夠監測一個值得變化,是一對多的關係,一個值的變化會通知全部的觀察者。
2》NSNotifaction是通知,一對多,在某些狀況下,KVO和NSNotifaction是同樣的,都是狀態變化以後告知對方。不一樣的是,NSNotifaction須要被觀察者先主動發出通知,而後觀察者註冊監聽後再來進行響應,比KVO多了發送通知這一步,可是其優勢是監聽不侷限與屬性的變化,還能夠對多種多樣的狀態進行監聽,監聽範圍廣,使用也更靈活。
3》delegate是代理,就是把本身不想作的事情交給別人去作,不須要關心中間須要作的事情,只要調用delegate就能夠了,由其餘類完成所須要的動做,因此是一對一的。
4》block是delegate的另外一種形式,是函數式編程的一種形式,使用場景和delegate同樣,相比delegate更爲靈活,並且實現也更直觀。
5》KVO通常的使用場景是數據,需求是數據變化。delegate通常的使用場景是行爲,須要別人幫忙作一件事情。NSNotifaction通常是進行全局通知,只須要發出通知就能夠,不關心你有沒有接受到通知。delegate是強關聯,就是委託和代理雙方都知道。
1》正確的複用cell
2》設計統一規格的cell
3》提早計算並緩存好高度,由於heightForRowAtIndexPath是調用最頻繁的方法
4》異步繪製,遇到複雜頁面,遇到性能瓶頸時,可能就是突破口
5》滑動時按需加載,這個在大量圖片展現,網絡加載的時候很管用
6》減小子視圖的層級關係
7》不要動態的add或者remove子控件,最好在初始化的時候就添加完,而後經過hidden來控制是否顯示。
管理方式:棧是編譯器自動管理,堆的釋放工做由程序員空
棧:在Windows下,棧是向低地址擴展的數據結構,是一塊連續的內存區域。這句話的意思是棧頂的地址和棧的最大容量是系統預先設計好的。在windows 下,棧的大小是2M(也有的說是1M),若是申請的空間超過棧的剩餘空間是,將提示overFlow,所以,能從棧得到的空間較小。
堆:堆是向高笛子擴展的數據結構,是不連續的內存區域。堆得大小受限於計算機系統中有效的虛擬內存,因而可知,堆得到空間比較靈活,也比較大。
碎片問題:對於堆來說,頻繁的new/delete勢必會形成內存空間的不連續,從而形成大量的碎片,使程序效率下降。對於棧來說,則不會存在這個問題,由於棧是先進後出的隊列,他們是如此的一一對應,以致於永遠都不可能有一個內存塊從棧中間彈出分配方式:堆都是動態分配的,沒有靜態分配的堆。
棧有2種分配方式:靜態分配和動態分配。靜態分配是編譯器完成的,好比局部變量的分配。動態分配由alloca函數進行分配,可是棧的動態分配和堆是不一樣的,他的動態分配是由編譯器進行釋放,無需咱們手工實現。分配效率:棧是機器系統提供的數據結構,計算機會在底層對棧提供支持:分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執行,這就決定了棧的效率比較高。堆則是C/C++函數庫提供的,它的機制是很複雜的。
分類裏面有類名,方法列表,協議列表,可是沒有屬性列表,因此原則上來講,分類只能添加方法,不能添加屬性的。固然,添加屬性也能夠,只要不去調用他。由於添加的屬性沒有get和set方法,雖然咱們能夠用runtime去動態的添加set和get方法,可是調用屬性的時候仍是不會經過的,由於他沒有實例變量。
分類裏邊添加的方法,即便不實現也是不會報錯的,由於分類是在運行時添加到類裏邊去的。可是擴展添加的方法必需要實現,由於擴展是在編譯時添加進去的。
分類裏邊添加的方法若是和原有類中的方法重名,則會優先調用分類中的方法,所以儘可能不要覆蓋原有類中的方法。
擴展添加的屬性默認是私有的,擴展沒有獨立的實現部分,也就是說,擴展中所聲明的方法必須依託對應的類的實現部分來實現。
用atomic生成的set和get方法會進行加鎖操做,這個鎖僅僅保證了存取方法的線程安全,並不是真正意義上的線程安全,由於線程安全還有除了讀寫以外的其餘操做(好比:當一個線程正在進行讀取方法的操做時,同時又有一個線程在進行release操做,可能會直接出現crash)
atomic 更耗費資源,速度要慢,若是沒有多線程之間的通信,儘可能仍是使用nonatomic。
舉例:當幾個線層同時調用同一屬性的讀取方法時,會get到一個完整的值,可是get的值不可控
線程1 調用get
線程2 調用set
線程3 調用set
這3個線程同時執行,線程1 會get到一個值,可是get到的值不可控,有多是線程2 線程3 以前的原始值,也有多是線程2 線層3 set以後的值
nonatomic 生成的讀取方法沒有加鎖,線程不安全,可是更快,當同一個線程同時訪問同一個屬性時,會出現沒法預料的結果。
被weak修飾的對象在釋放時會被置爲nil,不一樣於assign。
runtime 維護了一個weak 表,用於存儲指向某個對象的全部weak 指針。weak表實際上是一個hash 表,key是所指對象的地址,value是weak指針的地址數組。
1》初始化時,runtime會調用objc_initWeak函數,初始化一個新的weak指針指向對象的地址
2》添加引用時,objc_initWeak函數會調用objc_storeWeak函數,objc_storeWeak的做用是更顯指針指向,建立對應的弱引用表。
3》釋放時,調用clearDeallocating函數。clearDeallocating函數首先根據對象地址獲取全部weak指針地址的數組,而後遍歷這個數組把其中的數據置爲nil,最後把這個entry從weak表中刪除,最後清理對象的記錄。
struct SideTable {
// 保證原子操做的自旋鎖
spinlock_t slock;
// 引用計數的 hash 表
RefcountMap refcnts;
// weak 引用全局 hash 表
weak_table_t weak_table;
}
struct weak_table_t {
// 保存了全部指向指定對象的 weak 指針
weak_entry_t *weak_entries;
// 存儲空間
size_t num_entries;
// 參與判斷引用計數輔助量
uintptr_t mask;
// hash key 最大偏移值
uintptr_t max_hash_displacement;
};
複製代碼
AssociationsManager裏面是由一個靜態AssociationsHashMap來存儲全部的關聯對象的。這至關於把全部對象的關聯對象都存在一個全局map裏面。而map的key是這個對象的指針地址(任意兩個不一樣對象的指針地址必定是不一樣的),而這個map的value又是另一個AssociationsHashMap,裏面保存了關聯對象的kv對。
在obj dealloc 的時候會調用object_dispose,檢查有無關聯對象,有的話就_object_remove_assocations刪除
當觀察某對象A時,KVO機制動態建立一個對象A當前的子類,並未這個新的子類重寫了被觀察屬性keyPath 的 setter 方法。setter 方法隨後負責通知觀察對象屬性的改變情況。
使用方法,可實現取消系統kvo,本身觸發,也就可控。
+(BOOL)automaticallyNotifiesObserversForKey:(NSString *)key{
if ([key isEqualToString:@"name"]) {
return NO;
}else{
return [super automaticallyNotifiesObserversForKey:key];
}
}
-(void)setName:(NSString *)name{
if (_name!=name) {
[self willChangeValueForKey:@"name"];
_name=name;
[self didChangeValueForKey:@"name"];
}
}複製代碼
objc類中的屬性、方法還有遵循的協議等消息都保存在class_rw_t中;
其中還有一個指向常量的的指針ro,其中存儲到了當前類在編譯器就已經肯定的屬性、方法以及聽從的協議。
內省方法:
判斷對象類型:
-(BOOL) isKindOfClass:判斷是不是這個類或者這個類的子類的實例
-(BOOL) isMemberOfClass:判斷是不是這個類的實例
判斷對象or類是否有這個方法
-(BOOL) respondsToSelector:判斷實例是否有這樣方法
+(BOOL) instancesRespondToSelector: 判斷類是否有這個方法
object_getClass:得到的是isa的指向
self.class:當self是實例對象的時候,返回的是類對象,不然返回自身。類方法class,返回的是self,因此當查找meta class,須要類對象調用object_getClass方法。
沒有修飾,被block捕獲,是值拷貝。
使用_block修飾,會生成一個結構體,複製int的引用地址,達到修改數據。
涉及到捕獲的時候該變量是存在的,在執行block的時候可能被捕獲對象釋放了。
Runloop的做用是用來管理線程的,當線程的Runloop開啓後,線程就會在執行任務後,處於休眠狀態,隨時等待接受新的任務,而不是退出。
只有主線程的Runloop是默認開啓的,因此線程在開啓後,纔會一直運行,不會退出。其餘線程的Runloop若是須要開啓,就須要手動開啓。
在Runloop內部有一個判斷循環的條件,若是知足條件,就一直循環,線程獲得喚醒事件被喚醒,事件處理完畢之後,回到睡眠狀態,等待下次喚醒。
設置了一下屬性時,都會觸發離屏渲染:
1》shouldRasterize(光柵化)
2》masks(遮罩)
3》shadows(陰影)
4》edge antialiasing(抗鋸齒)
5》group opacity(不透明)
6》複雜形狀設置圓角等
7》漸變
__weak
修飾時block爲__NSStackBlock,存儲在棧區。1》共同點:block和delegate的方法均可以理解成回調函數,當某件事情發生的時候執行一段代碼片斷。
2》block優勢:是一種輕量級的回調,可以直接訪問上下文,使用塊的地方和塊的實現地方在同一個地方,使得代碼組織更加連貫。
3》delegate:相對來講是重量級的回調,由於方法的生命和實現分離開來,代碼的連貫性不是很好,代理不少時候都須要存儲一些臨時數據。代理的回調函數能夠是一組多個函數,在不一樣的時機調用不一樣的回調函數。
4》怎麼選擇:當回調函數多餘3個的時候,採用代理比較好;使用代碼塊容易形成循環引用,代理不會出現該問題;其餘狀況下優先考慮代碼塊。
1》[ViewController initWithCoder:]
或[ViewController initWithNibName:Bundle]
:首先從歸檔文件中加載UIViewController
對象。即便是純代碼,也會把nil
做爲參數傳給後者。
2》[UIView awakeFromNib]:
做爲第一個方法的助手,方法處理一些額外的設置。
3》[ViewController loadView]
:建立或加載一個view
並把它賦值給UIViewController
的view
屬性。
[ViewController viewDidLoad]
: 此時整個
視圖層次(view hierarchy)
已經放到內存中,能夠移除一些視圖,修改約束,加載數據等。
4》[ViewController viewWillAppear:]
: 視圖加載完成,並即將顯示在屏幕上。還沒設置動畫,能夠改變當前屏幕方向或狀態欄的風格等。
5》[ViewController viewWillLayoutSubviews]
即將開始子視圖位置佈局
6》[ViewController viewDidLayoutSubviews]
用於通知視圖的位置佈局已經完成
7》[ViewController viewDidAppear:]
:視圖已經展現在屏幕上,能夠對視圖作一些關於展現效果方面的修改。
8》[ViewController viewWillDisappear:]
:視圖即將消失
9》[ViewController viewDidDisappear:]
:視圖已經消失
10》[ViewController dealloc:]
:視圖銷燬的時候調用
1》當程序第一次運行而且將要顯示窗口的時候執行該方法
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
2》程序進入後臺的時候須要先執行程序取消活躍的方法
- (void)applicationWillResignActive:(UIApplication *)application
3》當程序進入後臺的時候
- (void)applicationDidEnterBackground:(UIApplication *)application
4》當程序將要進入前臺的時候
- (void)applicationWillEnterForeground:(UIApplication *)application
5》當程序變得活躍的時候
- (void)applicationDidBecomeActive:(UIApplication *)application
6》當程序將要退出的時候
- (void)applicationWillTerminate:(UIApplication *)application
若是程序在後臺能夠運行,則上面的方法會被替換成applicationDidEnterBackground
在計算機科學中,反射是指計算機程序在運行時(Runtime)能夠訪問、檢測和修改它自己狀態或行爲的一種能力。用比喻來講,反射就是程序在運行的時候可以「觀察」而且改變本身的而行爲。
要注意術語「反射」和「內省」的關係:內省機制僅指程序在運行時對自身信息的檢測;反射機制不只包括要能在運行時對程序自身信息進行檢測,還要求程序能進一步根據這些信息改變程序狀態或結構。
一個重點是改變,一個重點是檢測。
好比經過類名,生成類 Class * tempClass = NSClassFromString(str);
爲類增長方法等。
GCD是基於C的底層API,NSOperation屬於object-c類。
相對於GCD:
1》NSOperation擁有更多的函數可用
2》在NSOperationQueue中,能夠創建各個NSOperation之間的依賴關係。
3》有KVO,能夠檢測NSOperation是否正在執行,是否結束,是否取消
4》NSOperationQueue能夠方便的管理開發
5五、OC中建立線程的方法是什麼?若是在主線程中執行代碼,方法是什麼?
// 建立線程的方法
- [NSThread detachNewThreadSelector:nil toTarget:nil withObject:nil]
- [self performSelectorInBackground:nil withObject:nil];
- [[NSThread alloc] initWithTarget:nil selector:nil object:nil];
- dispatch_async(dispatch_get_global_queue(0, 0), ^{});
- [[NSOperationQueue new] addOperation:nil];
// 主線程中執行代碼的方法
- [self performSelectorOnMainThread:nil withObject:nil waitUntilDone:YES];
- dispatch_async(dispatch_get_main_queue(), ^{});
- [[NSOperationQueue mainQueue] addOperation:nil];
複製代碼
static id _instance;
+ (id)allocWithZone:(struct _NSZone *)zone {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [super allocWithZone:zone];
});
return _instance;
}
+ (instancetype)sharedData {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[self alloc] init];
});
return _instance;
}
- (id)copyWithZone:(NSZone *)zone {
return _instance;
}複製代碼
AFNetworking主要是對NSURLSession和NSURLConnection(iOS9.0廢棄)的封裝,其中主要有如下類:
1). AFHTTPRequestOperationManager:內部封裝的是 NSURLConnection, 負責發送網絡請求, 使用最多的一個類。(3.0廢棄)
2). AFHTTPSessionManager:內部封裝是 NSURLSession, 負責發送網絡請求,使用最多的一個類。
3). AFNetworkReachabilityManager:實時監測網絡狀態的工具類。當前的網絡環境發生改變以後,這個工具類就能夠檢測到。
4). AFSecurityPolicy:網絡安全的工具類, 主要是針對 HTTPS 服務。
5). AFURLRequestSerialization:序列化工具類,基類。上傳的數據轉換成JSON格式
(AFJSONRequestSerializer).使用很少。
6). AFURLResponseSerialization:反序列化工具類;基類.使用比較多:
7). AFJSONResponseSerializer; JSON解析器,默認的解析器.
8). AFHTTPResponseSerializer; 萬能解析器; JSON和XML以外的數據類型,直接返回二進
制數據.對服務器返回的數據不作任何處理.
9). AFXMLParserResponseSerializer; XML解析器;複製代碼
SDWebImage 中爲 UIImageView 提供了一個分類UIImageView+WebCache.h, 這個分類中有一個最經常使用的接口sd_setImageWithURL:placeholderImage:,會在真實圖片出現前會先顯示佔位圖片,當真實圖片被加載出來後再替換佔位圖片。
加載圖片的過程大體以下:
1.首先會在 SDWebImageCache 中尋找圖片是否有對應的緩存, 它會以url 做爲數據的索引先在內存中尋找是否有對應的緩存
2.若是緩存未找到就會利用經過MD5處理過的key來繼續在磁盤中查詢對應的數據, 若是找到了, 就會把磁盤中的數據加載到內存中,並將圖片顯示出來
3.若是在內存和磁盤緩存中都沒有找到,就會向遠程服務器發送請求,開始下載圖片
4.下載後的圖片會加入緩存中,並寫入磁盤中
5.整個獲取圖片的過程都是在子線程中執行,獲取到圖片後回到主線程將圖片顯示出來
SDWebImage原理:
調用類別的方法:
1. 從內存(字典)中找圖片(當這個圖片在本次使用程序的過程當中已經被加載過),找到直接使用。
2. 從沙盒中找(當這個圖片在以前使用程序的過程當中被加載過),找到使用,緩存到內存中。
3. 從網絡上獲取,使用,緩存到內存,緩存到沙盒。複製代碼
若是圖片較大,使用次數少,建議使用imageWithContentOfFile來加載圖片(相冊、版本新特性)
首先咱們須要明確,對象的內存通常被分配到堆上,基本數據類型和oc數據類型的內存通常被分配在棧上。
若是用assign修飾對象,當對象被釋放後,指針的地址仍是存在的,也就是說指針並無被置爲nil,從而形成了野指針。由於對象是分配在堆上的,堆上的內存由程序員分配釋放。而由於指針沒有被置爲nil,若是後續的內存分配中,恰好分配到了這塊內存,就會形成崩潰。
而assign修飾基本數據類型或oc數據類型,由於基本數據類型是分配在棧上的,由系統分配和釋放,因此不會形成野指針。
id是一個比較靈活的對象指針,而且是一個指向任何一個繼承自Object(或者NSObject)類的對象,而在cocoa的開發環境裏,NSObject是全部類的根類,因此id能夠指向任何一個cocoa的合法對象。
typedef struct objc_object {
Class isa;
} *id;複製代碼
id和NSObject的區別:
NSObject是一個靜態數據類型,id是一個動態數據類型,默認狀況下全部的數據類型都是靜態數據類型。
+ (void)load;
1.對於加入運行期系統的類以及分類,一定會調用此方法,且僅調用一次。
2.iOS會在應用程序啓動的時候調用load方法,在main函數以前調用
3.執行子類的load方法前,會先執行全部超類的load方法,順序爲父類->子類->分類
4.load方法不聽從繼承規則,若是類自己沒有實現load方法,那麼系統就不會調用,無論父類有沒有實現
5.儘量的精簡load方法,由於整個應用程序在執行load方法時會阻塞,即,程序會阻塞知道全部的load方法執行完畢,纔會繼續
7.load方法中最經常使用的就是方法交換 method swizzling複製代碼
+ (void)initialize;
1.在首次使用該類以前有運行期系統(非人爲)調用,且僅調用一次
2.惰性調用,只有當程序使用相關類時,纔會調用
3.若是類未實現initialize方法,而其超類實現了,那麼會運行超類的實現代碼,且會運行兩次,且第一次打印出來是父類,第二次打印出來是子類
4.initialize遵循繼承規則
5.初始化子類的時候會優先初始化父類,而後調用父類的initialize方法,而子類沒有覆寫initialize方法,所以會再次調用父類方法
複製代碼
一般狀況下每一個OC對象的最開始處都有一個隱藏的數據成員isa,isa保存有類的描述信息(包含方法數組列表和緩存)
struct objc_class {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class _Nullable super_class
OBJC2_UNAVAILABLE;
const char * _Nonnull name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE;
struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE;
struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE;
struct objc_protocol_list * _Nullable protocols
OBJC2_UNAVAILABLE;#endif
} OBJC2_UNAVAILABLE;複製代碼
經過isa指針,去objc_cache裏面查找是否有緩存的方法,若是有,則直接調用,若是沒有則去objc_method_list裏面去尋找對應的方法的實現,若是再找不到,就進入到消息轉發的階段了。
AF2.x 首先須要在子線程去start connection,請求發送成功後,所在的子線程須要保活以保證正常接收到NSURLConnectionDelegate回調方法。若是每來一個請求就開闢一條線程,而且保活線程,這樣開銷就太大了。因此只須要保活一條固定的線程,在這個線程裏發起請求,接收回調。
AF3.x爲何不須要常駐線程?
NSURLSession發起的請求,再也不須要在當前線程進行代理方法的回調,能夠指定回調的delegateQueue,這樣咱們就不用爲了等待代理回調方法而苦苦保活線程了。