?OC的動態(tài)性:會把編譯和鏈接是需要執(zhí)行的邏輯延遲到運行時,例如使用 id 所修飾的變量會在運行的時候才確定具體類型是什么,runtime 的方法交換等。
循環(huán)引用:當一個對象間接或直接地持有另一個對象与斤,而這個對象又有強指針指向該對象,就會引起循環(huán)應用無法釋放的問題。
1.block的使用 使用 weakSelf處理
2.delegate 作為屬性用weak修飾幽告,也可以防止野指針的出現(xiàn)
3.NSTimer 最為成員變量梅鹦。解決方式
在程序中除了在 dealloc方法去明確使用 invalid 然后賦值為nil
如果無法明確知道什么時候才可以停止裆甩,可以添加了一個類別讓原來的通過@selector執(zhí)行任務的方式轉換為block的方式冗锁。
+ (NSTimer *)xx_scheduledTimerWithTimeInterval:(NSTimeInterval)interval
block:(void(^)())block
repeats:(BOOL)repeats
{
return [self scheduledTimerWithTimeInterval:interval
target:self
selector:@selector(xx_blockInvoke:)
userInfo:[block copy]
repeats:repeats];
}
+ (void)xx_blockInvoke:(NSTimer *)timer {
void (^block)() = timer.userinfo;
if(block) {
block();
}
}
然后當控制釋放的時候,停止定時器就可以
-(void)dealloc{
NSLog(@"dealloc");
[self.timer invalidate];
self.timer = nil;
NSLog(@"timer:%@",self.timer);
}
屬性修飾
assign:基本數(shù)據(jù)類型嗤栓,結構體
weak:delegate(野指針冻河,循環(huán)引用),IB引進來的UI控件(視圖層級結構)
copy:不可變類型(指向不同對象)茉帅,block(保證是放在堆上)
strong:修飾對象叨叙,強引用
retain:和strong類似,在修飾block的時候作用相當于assign
類別作用:
在保持原有類的情況下堪澎,增加其方法(UIScrollView擂错,圖片緩存裁剪處理)
講一個龐大的類根據(jù)作用分解到不同的類別中,便于維護
static修飾的變量并不會改變作用范圍樱蛤,改變的只是內存分配方式(存放在靜態(tài)區(qū)在整個運行期間一直存在)
數(shù)據(jù)持久化:原理都是數(shù)據(jù)保存到本地文件中
1.屬性列表:一般使用NSUserDefaults操作(沙盒l(wèi)ibrary/preference)
2.對象歸檔:將對象轉化為NSData寫入帶本地文件钮呀,對象需要實現(xiàn)NSCoding協(xié)議
[NSKeyedArchiver archiveRootObject:self toFile:fileName];
3.SQLite3:FMDB封裝庫
4.Core Data:對SQLite基于面向對象的封裝
棧區(qū)(stack)由編譯器自動分配釋放,存放方法(函數(shù))的參數(shù)值,局部變量的值等,是一塊連續(xù)的內存的區(qū)域昨凡。即棧頂?shù)牡刂泛蜅5淖畲笕萘渴窍到y(tǒng)預先規(guī)定好的爽醋。
堆區(qū)(heap)一般由程序員分配釋放,是不連續(xù)的內存區(qū)域,從而堆獲得的空間比較靈活便脊。有我們去new/alloc來創(chuàng)建的對象蚂四,就是放在堆下面。
棧區(qū)(stack)由編譯器自動分配釋放,存放方法(函數(shù))的參數(shù)值,局部變量的值等哪痰,是一塊連續(xù)的內存的區(qū)域遂赠。即棧頂?shù)牡刂泛蜅5淖畲笕萘渴窍到y(tǒng)預先規(guī)定好的。
堆區(qū)(heap)一般由程序員分配釋放,是不連續(xù)的內存區(qū)域晌杰,從而堆獲得的空間比較靈活解愤。有我們去new/alloc來創(chuàng)建的對象,就是放在堆下面乎莉。
結構體:
struct CGPoint {
CGFloat x;
CGFloat y;
};
typedef struct CGPoint CGPoint;
TableViewCell \ 頁面優(yōu)化:
1.盡量減少透明圖層的使用來減少渲染次數(shù)送讲,opaque = YES
2.減少對象的創(chuàng)建或者使用更為輕的對象,如當視圖元素不需要響應用戶的觸摸事件使用CALayer代替UIView
3.當大量文字需要顯示惋啃,cpu需要耗費比較多的資源去進行渲染和排版哼鬓,所以這個時候可以選擇CoreText 來處理
4.避免大圖使用,程序解碼比較耗時
5.復雜布局使用autoLayout會影響性能边灭,更好的是選擇手動布局
6.使用CoreGraphics進行繪制的時候异希,如果繪制比較耗時,可以異步處理后再返回主線程顯示
7.TableViewCell的重用绒瘦,避免在heightForCell方法進行較多的處理称簿,將動態(tài)高度的緩存
7.離屏渲染(系統(tǒng)會在屏幕緩沖外開辟新的緩沖去處理)扣癣,設置shadow時候不設置shadowPath,在設置圓角不同時使用 maskToBound和cornerRdius有時會導致憨降,或者使用CAShapeLayer 和BezierPath結合的的方式繪制圓角父虑。
7.如果不需要要顯示透明圖層,那么將試圖的opaque設置為YES(默認)授药,會讓系統(tǒng)會將試圖作為不透明去處理而加快渲染士嚎。
但如果需要使用到透明,則設置為NO悔叽。
8.減少視圖的層級結構
4.可以根據(jù)需要是使用預加載或者延遲加載莱衩。
8.使用Instrument工具去檢測
線程加鎖 : 解決多線程同時訪問同一資源導致的問題,一般通過加鎖處理或者使用串行隊列處理:
//串行隊列
dispatch_queue_create("", DISPATCH_QUEUE_SERIAL), ^ {
}
1.GCD信號量
+(NSString*)getContacts{
//獲取通訊錄權限
ABAuthorizationStatus authStatus = ABAddressBookGetAuthorizationStatus();
if(authStatus != kABAuthorizationStatusAuthorized)
{
//是否有通訊錄權限
__block BOOL accessGranted = NO;
ABAddressBookRef tmpAddressBook = ABAddressBookCreateWithOptions(NULL,NULL);
dispatch_semaphore_t sema=dispatch_semaphore_create(0);//創(chuàng)建信號量 為0
ABAddressBookRequestAccessWithCompletion(tmpAddressBook, ^(bool granted,CFErrorRef error){
accessGranted = granted;
dispatch_semaphore_signal(sema);//信號量 +1
});
//當信號量 > 0 才繼續(xù)運行娇澎,并且信號量 - 1
dispatch_semaphore_wait( sema, DISPATCH_TIME_FOREVER);
if(accessGranted ==NO){
return @"[]";
}
}
//讀取聯(lián)系人----------此處省略聯(lián)系人讀取步驟-------------------}
2.NSLock *lock = [NSLock alloc]init];
[lock lock];
.....
[lock unlock];
3.條件鎖(基于信號量)
NSConditionLock *conditionLock = nil;
BOOL canLock = [conditionLock tryLockWhenCondition:kCondition_A];
if (canLock) {
FDLog(@"線程A lock, 請等待");
[conditionLock unlock];
}else{
FDLog(@"線程A 條件不滿足笨蚁,未加lock");
}
4.NSRecursiveLock 遞歸鎖,同一個線程可以多次加鎖趟庄,但是不會引起死鎖,如果是NSLock括细,則會導致崩潰
- (void)reverseDebug:(NSUInteger )num lock:(NSRecursiveLock *)lock
{
? ? ?[lock lock];
? ? if (num<=0) {
? ? ? ? ?FDLog(@"結束");
? ? ? ? ?return;
? ? }
? ? [self reverseDebug:num-1 lock:lock];//遞歸
? ? [lock unlock];//還是需要解鎖
}
5.@synchronized(self) { ? ? ? ?
? ? ? ...
}
6.atomic的線程安全只限于setter和getter方法。會在setter方法里面加鎖岔激。
當我們去啟動 RunLoop勒极,系統(tǒng)會自動在內部創(chuàng)建自動釋放池。
數(shù)組遍歷
當使用block的方式進行遍歷虑鼎,會阻塞線程辱匿,直到遍歷結束。
UIView的 drawRect炫彩,layoutSubviews 方法調用時機:
兩者都是在視圖將要顯示(viewWillAppear之后匾七,viewDidAppear之前調用,layoutSubviews只要addSubviews就可以調用江兢,但是drawRect方法必須設置了frame才能調用昨忆,否則就不會被調用)
layoutSubviews
1、init初始化不會觸發(fā)layoutSubviews杉允。
2邑贴、addSubview會觸發(fā)layoutSubviews
3、設置view的Frame會觸發(fā)layoutSubviews叔磷,當然前提是frame的值設置前后發(fā)生了變化
4拢驾、滾動一個UIScrollView會觸發(fā)layoutSubviews
5、旋轉Screen會觸發(fā)父UIView上的layoutSubviews事件
6改基、改變一個UIView大小的時候也會觸發(fā)父UIView上的layoutSubviews事件
7繁疤、調用setNeedsLayout(延時到下個更新周期調用)
drawRect(在調用前會先調用sizeToFit方法,可以再這個方法計算坐標處理)
1.在UIView初始化時設置rect大小,drawRect 就會自動調用(在視圖將要顯示時候調用稠腊,只調用一次,viewDidLoad兩方法之后掉用的)躁染,否則不被自動調用。
2.調用setNeedsDisplay(異步執(zhí)行)
layoutSubviews:UIView 需要對子控件進行手動的布局架忌,則可以重寫此方法吞彤。只有在autoresizing和constraint-based behaviors of subviews不能提供我們想要的布局結果的時候,我們才應該重寫此方法鳖昌。
layoutSubviews方法調用先于drawRect
MVC優(yōu)點:
體現(xiàn)在低藕性與重用性:
數(shù)據(jù)層與視圖層的互相獨立备畦,可單獨地對某一模塊進行改變低飒,而不會影響到其余模塊许昨,也可以根據(jù)實際需要靈活地重用各個模塊。
NSOperation與GCD區(qū)別:
GCD是基于C語言的一套api褥赊;而NSOperaion底層是基于GCD開發(fā)糕档,因此效率方面GCD更好。
而NSOperation更適用于一些復雜的任務:
1.可以對隊列暫停拌喉,恢復速那,取消操作(NSOperationQueue cancelAllOperations setSuspended),不過這里暫停并不是暫停當前的任務而是下一個任務尿背,恢復會從第一個沒有執(zhí)行的任務開始端仰。
2.可以建立任務間的依賴關系(NSOperation setDependency)
3.NSBlockOperation NSInvocationOperation可以設置任務的優(yōu)先級(setQueuePriority),
而GCD只可以設置隊列的優(yōu)先級.
TCP三次握手:
客戶端向服務端發(fā)送請求 - 服務端返回數(shù)據(jù)包給客戶端 - 客戶端返回響應包給服務端田藐,連接建立
TCP釋放連接四次握手:
客戶端向服務端發(fā)送斷開請求 - 服務端接收到請求后先返回響應給客戶端荔烧,然后連接斷開后再返回一次數(shù)據(jù)包給客戶端- 客戶端收到服務端的返回,返回響應給服務端汽久。
9.CoreData多線程安全處理
CoreData包含(實體對象鹤竭,模型對象,上下文景醇,持久化存儲協(xié)調器)
線程注意點:
1.manageObject,manageObjectContext只能在自己的線程處理臀稚,不能跨線程
2.對于持久化存儲協(xié)調器(NSPersistentStoreCoordinator)可以多線程共享
3.magageObject的線程間傳遞通過id,并且通過objectWithID來獲取
解決方法:
共同使用一個 NSPersistentStoreCoordinator三痰,以及兩個獨立的 Contexts,一個context 負責主線程與UI協(xié)作吧寺,一個context在后臺負責耗時的處理,用Notifications的方式通知主線程的NSManagedObjectContext進行mergeChangesFromContextDidSaveNotification 對變化進行合并處理。
//這個通知是系統(tǒng)定義的通知
[[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextDidSaveNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *note) {
if (note.object == self.privateContext) {
dispatch_async(dispatch_get_main_queue(), ^{
//返回主線程合并處理散劫,這里的note.object不能再主線程進行使用稚机,需要合并處理
[self.mainContext performBlock:^{
[self.mainContext mergeChangesFromContextDidSaveNotification:note];
}];
});
}
}];
14.網(wǎng)絡安全:
1.為了防止非法使用api,在每次向服務器請求的使用舷丹,將appKey和加密后的appSecret也發(fā)送給服務器抒钱,服務器根據(jù)appKey找到對應的appSecret與從客戶端傳遞過來進行比對,一致的話就是合法請求。(appkey 和 secret key相當于當前賬戶的另外一套賬號和密碼機制)
2.使用https協(xié)議谋币。
82.常見的crash情況
1.訪問野指針仗扬,比如訪問一個已經釋放的對象的屬性方法(解決方式是當一個指針所指向的對象如果已被釋放,則將指針置nil)
2.訪問數(shù)組類對象越界或插入了空對象
3.訪問了不存在的方法
4.當某個對象會被多個線程修改(加鎖處理)
5.NSNotification KVO的非對稱添加刪除(訪問野指針)
數(shù)據(jù)庫事務處理
當我們對數(shù)據(jù)庫進行更新操作時蕾额,默認會將操作一條條地往數(shù)據(jù)庫提交早芭。而使用事務處理,則是將所有的操作一次性提交給數(shù)據(jù)庫诅蝶,當處理的過程中出現(xiàn)問題退个,則可以進行回滾操作不進行任何修改,保證數(shù)據(jù)的完整性调炬。
所以當需要對大量的數(shù)據(jù)進行更新操作時语盈,使用事務在效率和安全性都會大大提高。
16.斷點續(xù)傳
//使用HEAD方法缰泡,僅獲取目標文件的信息刀荒,而不做實際的下載工作。
//[request setHTTPMethod:@"HEAD"];
/**
設置斷點續(xù)傳的思路:
HeaderField:頭域(請求頭部的字段)
可以通過指定range的范圍逐步地下載指定范圍內的數(shù)據(jù)棘钞,待下載完成后缠借,再將這些數(shù)據(jù)拼接成一個文件。
1根據(jù)HEAD方法獲取到要下載的文件的總大小宜猜、
2在磁盤上建立一個臨時的緩沖文件泼返,該文件的大小與目標文件大小一致
3緩沖文件中所有字節(jié)都是默認為0
4開啟多線程,分別加載不同的range頭指定的數(shù)據(jù)塊姨拥,待數(shù)據(jù)塊加載完成以后绅喉,將其分別寫入對應的偏移地址。
5所有數(shù)據(jù)下載完成以后垫毙,表示文件下載完成霹疫,將臨時文件名更改為目標文件。
開發(fā)的難點:
0在寫入文件之前综芥,首先要建立一個同等大小的文件丽蝎。
1文件的讀寫問題,在oc里默認是覆蓋膀藐,追加屠阻,如果要指定位置,需要用seek方法额各,移動文件指針国觉。
2在多線程寫入文件時,文件的鎖定操作是一個問題虾啦。
*/
[request setValue:@"bytes=0-499" forKeyPath:@"range"];//表di示只讀取數(shù)據(jù)的第0個字節(jié)到第499個字節(jié)麻诀。
線程間通信:
1.performSelectorOnMainThread痕寓,去主線程執(zhí)行
? ?performSelectorInBackground ,后臺線程執(zhí)行
2.通過NSMachPort端口
將端口添加到當前線程的runloop里,通過這個端口與其他線程進行消息的發(fā)送接收(通過delegate 來進行消息接受的回調蝇闭,通過回調方法傳遞過來的參數(shù)呻率,獲取對方的端口,通過端口就可以發(fā)送消息)呻引。
NSPort *myPort = [NSMachPort port];
//2. 設置port的代理回調對象myPort.delegate=self;
//3. 把port加入runloop礼仗,接收port消息
[[NSRunLoop currentRunLoop] addPort:myPort forMode:NSDefaultRunLoopMode];
- (void)handlePortMessage:(NSMessagePort*)message{
//
NSPort*localPort = [message valueForKeyPath:@"localPort"];
NSPort*remotePort = [message valueForKeyPath:@"remotePort"];
//使用端口發(fā)送消息
[remotePort sendBeforeDate:[NSDatedate]
msgid:kMsg2
components:nilfrom:localPort
reserved:0];
}
APP通信方式:
1.URL Scheme:App1通過openURL的方法跳轉到App2,并且在URL中帶上想要的參數(shù)(需要在info.plist中配置好URL types)逻悠,常用于 分享到微信朋友圈微博等功能元践。
2.Keychain:微信登陸,使用同一個賬號平臺童谒,實現(xiàn)自動登錄其他的平臺单旁。每個程序都有一個獨立的keychain存儲,只需要使用對應的登錄SDK惠啄,通過共享keychain中的數(shù)據(jù)慎恒,那么就可以實現(xiàn)統(tǒng)一賬戶登錄了任内。(比如密碼撵渡、證書等等,就需要使用更為安全的keychain了死嗦。keychain里保存的信息不會因App被刪除而丟失趋距,在用戶重新安裝App后依然有效,數(shù)據(jù)還在越除。它是一個sqlite數(shù)據(jù)庫节腐,其保存的所有數(shù)據(jù)都是加密過的。)
3.UIPasteboard(剪切板功能):在淘寶app中將鏈接自定義成淘口令摘盆,引導用戶進行復制翼雀,并去QQ好友對話中粘貼。然后QQ好友收到消息進行粘貼后后再打開自己的淘寶app孩擂,淘寶app每次從后臺切到前臺時狼渊,就會檢查系統(tǒng)剪切板中是否有淘口令,如果有淘口令就進行解析并跳轉到對于的商品頁面类垦。
繪制方式:
1.使用 drawInContext drawRect 方法狈邑,方法會自動創(chuàng)建畫布,只需要獲取上下文繪制蚤认。
2.手動創(chuàng)建畫布
UIGraphicsBeginImageContext(CGSizeMake(400,400));
//獲取上下文
CGContextRef context =UIGraphicsGetCurrentContext();
//使用CG來繪制
CGFloat lineWidth = 2.f;
CGRect allRect =CGRectMake(0, 0, 100, 100);
CGRect circleRect =CGRectInset(allRect, lineWidth/2.f, lineWidth/2.f);
CGPointcenter =CGPointMake(20, 20);
[[UIColor blueColor]setStroke];
[[UIColor grayColor]setFill];
CGContextSetLineWidth(context, lineWidth);
//繪制
CGContextStrokeEllipseInRect(context, circleRect);
//使用beizer繪制
CGFloat startAngle = - ((float)M_PI/ 2.f);
// Draw progress
UIBezierPath*processPath = [UIBezierPath bezierPath];
processPath.lineCapStyle=kCGLineCapButt;
processPath.lineWidth= lineWidth * 2.f;
CGFloatradius = 30;
CGFloatendAngle = 30 + startAngle;
[processPath addArcWithCenter:centerradius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];
[[UIColor blackColor]set];
[processPath stroke];
//獲取繪制的圖片
UIImage* im =UIGraphicsGetImageFromCurrentImageContext();
//關閉上下文
UIGraphicsEndImageContext();
//將繪制的圖片顯示處理
UIImageView*imageView = [[UIImageViewalloc]initWithFrame:CGRectMake(50, 50, 200, 200)];
[self.view addSubview:imageView];
[imageView setImage:im];
socket長連接設計(AsyncSocket):
使用單例模式維持一個長連接米苹,并且定時地向服務器發(fā)送心跳包來判斷是否在連接中,否則重新連接砰琢≌核唬客戶端需要檢測連接狀態(tài)良瞧,通過delegate來對連接狀態(tài)進行回調,包括:正在連接训唱,連接中莺褒,連接斷開,重新連接雪情。并且提供對應的方法讓用戶去進行一些常用的操作遵岩,包括:開始連接,退出登錄后的斷開連接巡通,消息的收發(fā)等
當const修飾一個指針變量的時候尘执,可以指定指針不可修掛,或者指針指向的數(shù)據(jù)不可修改
const int *a(數(shù)據(jù)不可修改宴凉,指針可以) ?int *const a(指針可修改誊锭,數(shù)據(jù)不可變)
UIView,UIViewController,UIApplication直接繼承自UIResponder,而UIWindow繼承自UIView弥锄,UIResponder 下面有對應的響應用戶觸摸的方法
watchdog超時機制:
當應用未能及時響應用戶界面事件丧靡,如在主線程操作網(wǎng)絡,文件操作等耗時操作導致程序卡主了籽暇,就會會殺死程序并生成watchdog超時日志温治。
38.觀察者模式:
是一種訂閱-發(fā)布模式〗溆疲可以同時對一個對象進行觀察熬荆,當對象的狀態(tài)發(fā)生改變,觀察者就會接收到對應的通知绸狐,他的優(yōu)點在于觀察者與消息發(fā)布者并不需要知道對方的細節(jié)卤恳,只需要做好自己的業(yè)務,并且觀察者的數(shù)量并沒有限制寒矿,是一種低藕的一對多的觀察方式突琳。
在ios里典型的就是NSNotification和KVO,前者常用語系統(tǒng)的事件通知,如鍵盤事件符相,前后臺切換拆融,或者模塊之間的通信。KVO就是對對象屬性的觀察主巍。
struct class 區(qū)別:
struct可以繼承冠息,可以多態(tài),可以定義函數(shù)孕索,和class最大區(qū)別在于變量class的默認訪問控制是private逛艰,而struct默認是public;對于對象內存的管理有系統(tǒng)的回收機制處理搞旭,而 struct 定義的對象則是在使用完畢后自動清理分配的內存散怖。
當需要有大量的邏輯處理使用類菇绵,如果只是CGPoint,CGSize這些輕量結構镇眷,使用struct咬最。
枚舉typedef NS_ENUM
使用情景:當需要列舉的狀態(tài)有限的,并且數(shù)量不多(3-4左右)欠动,使用枚舉
沙盒機制(用來存放非代碼文件(圖片,音頻,視頻,屬性列表(plist), sqlite數(shù)據(jù)庫,文本文件,其他等等)):
Document文件夾用于保存程序運行中需要創(chuàng)建的文件永乌,如sqlite文件
Library Preferences:存放應用的偏好設置(有系統(tǒng)維護,不能直接去修改具伍,需要通過NSUserDefault來添加偏好設置)
Cache:緩存文件夾翅雏,在程序退出后不會刪除(iTunes不會備份)
tmp:臨時文件夾(在文件使用結束后刪除),在手機重啟目錄文件會被刪除人芽;在內存底的情況下也可能會被刪除望几,不會被iTunes備份
.app文件包,應用程序本身萤厅,不能去修改橄抹。
如果你做個記事本的app,那么用戶寫了東西惕味,總要把東西存起來楼誓。那么這個文件則是用戶自行生成的,就放在documents文件夾里面赦拘。
如果你有一個app慌随,需要和服務器配合,經常從服務器下載東西躺同,展示給用戶看。那么這些下載下來的東西就放在library/cache
//獲取沙盒主目錄路徑
NSString *homeDir = NSHomeDirectory();
//獲取Documents目錄路徑
NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
//獲取Library的目錄路徑
NSString *libDir = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) firstObject];
//獲取Caches目錄路徑
NSString *cachesDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
//獲取tmp目錄路徑
NSString *tmpDir =NSTemporaryDirectory();
進程
ios中app的運行是單進程的丸逸,進程是資源分配的基本單位蹋艺,而線程是cpu調度的基本單位,是進程中的一個實體黄刚。線程沒有獨立的存儲控件捎谨,進程下的線程共享該進程下的資源。
進程間通信方式:
1.管道
2.消息隊列
3.socket
4.共享內存(常用)
objc_msgForward消息轉發(fā)
當我們在對一個對象發(fā)送消息的時候憔维,運行時調用objc_msgSend方法涛救,根據(jù)累的分發(fā)表去尋找該方法,如果找不到就去父類找业扒,如果依然找不到就會調用objc_msgForward進行消息轉發(fā)检吆,首先它會嘗試去尋找在運行的時候是否動態(tài)地去實現(xiàn)了這個方法,如果沒有就去尋找有沒有其他的對象可以相應該方法程储,如果仍然沒有蹭沛,臂寝,則會調用forwardInvocation方法來來將消息轉發(fā)給其他的對象,如果以上三步都沒有處理掉就會跑出異常摊灭。
(_objc_msgForward是IMP類型咆贬,用于消息轉發(fā)的:當向一個對象發(fā)送一條消息,但它并沒有實現(xiàn)的時候)
BAD_ACCESS在什么情況下出現(xiàn)帚呼?
訪問了野指針掏缎,比如訪問已經釋放的對象的成員變量或者向他發(fā)消息
所以當指針變量所指向的對象內存被釋放掉后,需要對指針賦值為nil煤杀,防止產生“野指針”御毅。
檢測UIViewController內存泄漏的原理:
1、添加一個myDealloc方法并且在里面輸出對應的信息怜珍,在類方法load 里實現(xiàn)默認的dealloc 與自定義定位方法進行方法交換端蛆,那么根據(jù)打印處理的信息,就可以判斷一個VC有沒有釋放掉酥泛。
2今豆、利用ARC中weak變量不持有對象,并且在對象釋放時會自動置為nil的特性柔袁,在適當?shù)臅r候來檢測VC是否在內存駐留呆躲。
Left Join[左聯(lián)結]
返回包括左表中的所有記錄和右表中聯(lián)結字段相等的記錄
Right Join[右聯(lián)結]
返回包括右表中的所有記錄和右表中聯(lián)結字段相等的記錄
Inner Join[等值聯(lián)結]
只返回兩個表中字段相等的行
sqlite優(yōu)化:
1.查詢優(yōu)化:索引建立(防止全文檢索,防止索引建立太多)
2.大量的更新操作:事務(效率捶索,安全)
3.表的建立(靈活弟孟,字段設置)
網(wǎng)絡請求中如何提高性能
1.在于服務器交換的數(shù)據(jù)格式方面,gson要比xml效率高别惦,如果使用xml那么在大量數(shù)據(jù)的情況下使用基于事件的解析方式要比dom樹的方式效率高
2.對請求響應的數(shù)據(jù)進行壓縮 gzip
3.對請求數(shù)據(jù)進行緩存,可以使用系統(tǒng)默認的NSURLCache 對GET請求進行緩存,只需要在請求時設置好對應的緩存策略趴腋。
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@""] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:3];
connection= [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];
ios 循環(huán)引用
1.計時器NSTimer,當我使用計時器時候址芯,內部會有一個引用指向VC哥捕,導致VC我發(fā)釋放,dealloc不會被調用构回。
2.delegate
3.block
如果賦值沒有通過setter方法或者KVC夏块,而是直接修改屬性對應的成員變量,例如:僅調用_name = @"newName"纤掸,這時是不會觸發(fā)kvo機制
KVO
typedef NS_OPTIONS(NSUInteger, NSKeyValueObservingOptions) {
NSKeyValueObservingOptionNew = 0x01,//改變后的值
NSKeyValueObservingOptionOld = 0x02,//改變前的值
NSKeyValueObservingOptionInitial NS_ENUM_AVAILABLE(10_5, 2_0) = 0x04, //addobserving之后會馬上調用observeValueForKeyPath脐供,不會等到值改變
NSKeyValueObservingOptionPrior NS_ENUM_AVAILABLE(10_5, 2_0) = 0x08//分2次調用。在值改變之前和值改變之后
};
FOUNDATION_EXPORT NSString *const NSKeyValueChangeNewKey;
FOUNDATION_EXPORT NSString *const NSKeyValueChangeOldKey;
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (context == (__bridge void*)self) {
if ([keyPath isEqualToString:kKeyPathForNavigationItemRightBarButtonItems]) {
//取值
NSArray *rightBarButtonItems = [change objectForKey:NSKeyValueChangeNewKey];
}
}
}
當我們通過KVO對對象屬性進行監(jiān)聽借跪,如果注冊的選項使用NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld政己,那么在接受消息出會將新和舊的值都會傳遞過來。如果加上NSKeyValueObservingOptionPrior選項那么在改變值得前后都會個發(fā)一次通知垦梆。
原來類似于手動觸發(fā)KVO通知(因為默認下類別添加的屬性因缺少setter getter方法而無法使用匹颤,通過runtime的關系屬性來添加屬性仅孩,如果需要對屬性的改變通過KVO進行監(jiān)聽,因為系統(tǒng)這個時候是不會自動觸發(fā)通知印蓖,所以就需要手動去觸發(fā)):
[self willChangeValueForKey:@"mj_footer"]; // KVO
objc_setAssociatedObject(self, &MJRefreshFooterKey,//修改屬性
mj_footer, OBJC_ASSOCIATION_ASSIGN);
[self didChangeValueForKey:@"mj_footer"];//KVO
72.MJRefresh基本原理
對于使用下拉刷新使用的header刷新控件和下拉加載的footer刷新控件都是將這些控件放在scrollview的可見區(qū)域外辽慕,而對于下拉加載的footer控件的添加則要判斷scrollview的contentSize高度和frame的高度,如果內容是超出可見區(qū)域content高度大于frame高度赦肃,則將footer空間添加到contentSize高度之后溅蛉,否則就加在frame的高度之后。
因為對于header還是footer刷新的動作都是通過KVO對scrollview的y軸偏移量變化來處理他宛,而整個下拉上拉的狀態(tài)可以在:默認狀態(tài)船侧,正在下拉,刷新中厅各,返回默認狀態(tài)這幾個狀態(tài)中镜撩,所以將他們的這些特性抽象出來他們的父類,在里面添加KVO的消息機制队塘,添加KVO所觸發(fā)的鉤子方法袁梗,不做任何實現(xiàn),具體實現(xiàn)在header,footer的類中根據(jù)偏移量的不同是處理不同的狀態(tài)變化憔古,重寫狀態(tài)屬性的setter方法遮怜,當偏移量發(fā)生改變,在對應的響應方法這里只需要判斷并且設置當前刷新狀態(tài)鸿市,而在狀態(tài)屬性的stter方法里锯梁,根據(jù)狀態(tài)的不同來設置不同的contentInset,視圖的改變焰情。
在這里為了table或者collection的方便添加Header或者footer陌凳,添加scrollview的類別,這樣就需要在里面使用到下拉刷新的header屬性和上啦加載的footer屬性烙样,這個時候就是用runtime機制的關系屬性的方法來處理冯遂,并且在這兩個setter方法添加KVO的手動觸發(fā)通知willChangeValueForKey和didChangeValueForKey。
73.通過UIPanGestureRecognizer實現(xiàn)控件的拖拽效果
-(void)panAction:(UIPanGestureRecognizer *)pan
{
//以self.playerView的左上角為坐標原點
//CGPoint point=[pan locationInView:self.pointView];
//獲取的點是以手指按下的點為原點的
CGPoint point1 = [pan translationInView:pan.view];
UIView *targetView = pan.view;
targetView.center = CGPointMake(targetView.center.x + point1.x, targetView.center.y + point1.y);
//清空位移數(shù)據(jù)谒获,避免拖拽事件的位移疊加
[pan setTranslation:CGPointZero inView:pan.view];
}
數(shù)據(jù)傳值方式
1.變量之間的數(shù)據(jù)傳遞
2.指針類型之間的地址傳遞
3.代理設置模式的數(shù)據(jù)傳值
4.通過的block傳遞
5.系統(tǒng)通知傳值(userInfo)
crash日志分析
在我們每次編譯(需要將debug的選項改為dsym)或打包版本時候都會自動產生一個dsym文件,這是一個16進制的函數(shù)地址映射文件壁却,首先檢查.dsym和.crash文件的UUID是一致的批狱,然后通過這個文件和崩潰日志.crash文件,使用XCODE自帶的symbolicatecrash命令行工具展东,就可以導出一個.log文件赔硫,里面就可以讓我們定位到程序哪里出問題。所以每次發(fā)布版本的時候就需要將.xcarchive文件夾保存下來盐肃,里面就有我們所需要的文件爪膊。這里還需要注意要权悟。
Time Profiler
按照固定的時間間隔來跟蹤每一個線程的堆棧信息,從而讓我們方便地看到程序運行過程中各個方法正在消耗CPU時間
id聲明的對象具有運行時的特性,知道運行時才回去決定他的類型推盛,即可以指向任意繼承自NSObject的對象
82.判斷cell是否在屏幕內
1. 獲取當前cell對于tableview的位置 rectForRowAtIndexPath
2.獲取table y軸上的偏移量峦阁,將cell的frame的y坐標 - 偏移量,獲取相對于內容視圖的位置
3.可視區(qū)域為table 的frame耘成,然后通過函數(shù) CGRectIntersectsRect 判斷兩個位置是否存在重疊
4.這里如果是加入到導航欄中的table榔昔,還需要考慮到contentInset內編劇
CGFloat offsetY = self.tableView.contentOffset.y;
CGRect contentRect = self.tableView.frame;
CGRect rectCell = [self.tableView rectForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
rectCell.origin.y = rectCell.origin.y - offsetY;
if(CGRectIntersectsRect(contentRect, rectCell)){
NSLog(@"再屏幕內");
}else{
NSLog(@"--不再屏幕內");
}
解決UITableView中Cell重用機制導致內容出錯的方法總結
1.不使用重用機制
// UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; //改為以下的方法
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; //根據(jù)indexPath準確地取出一行
每個cell指定不同的重用標識符
2.內容出錯往往是加載過慢導致內容沒有及時地更新,可以使用縮略圖瘪菌,顯示默認圖片撒会,預加載進緩存中等方式處理。
哪些途徑可以讓ViewController瘦下來
1.將視圖處理單獨封裝(如各種窗口师妙,cell)
2.將業(yè)務邏輯的處理诵肛,如網(wǎng)絡數(shù)據(jù)庫處理等可以放到對應的model里進行
Objective-C如何對【已有的方法】,添加自己的功能代碼以實現(xiàn)類似記錄日志這樣的功能默穴?
1.創(chuàng)建一個方法怔檩,在里面調用原有的方法,并且加上記錄功能
2.使用runtime 的方法交換壁顶,對原有方法和自定義的方法進行交換珠洗。
CADisplayLink保持著和屏幕刷新率形同的頻率進行回調
//創(chuàng)建對象
self.progressObjectDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateProgressFromProgressObject)];
//注冊到runloop中
[_progressObjectDisplayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];//停止
[self.displayLink invalidate];
self.displayLink = nil;
對于一些需要高頻率刷新以致到達流暢效果的,如動畫若专,繪制许蓖,視頻畫面等,一般使用TA调衰。
當我們使用readonly去修飾屬性膊爪,意味著不會生成setter方法,那么通過訪問方式如obj.name self.name這些實際就是訪問setter方法嚎莉,但是因為沒有所以這樣調用會報錯米酬,所以修改屬性的方法就是在類內部使用_name這種方式去修改。當然可以用KVC的方式去修改(setter方法->accessInstanceVariablesDirectly yes->成員變量_name _isName name isName->setValues forUndefineKey該方法默認拋異常,可以去重寫)
查找:
get<key>趋箩,<key>赃额,is<key>?的順序方法查找getter方法,如果沒找到回去找類似于<key>AtIndex類似的數(shù)組方法叫确。
+ (BOOL)accessInstanceVariablesDirectly,如果返回YES(默認行為)跳芳,那么和先前的設值一樣,會按_key,_isKey,key,isKey?的順序搜索成員變量名竹勉,這里不推薦這么做飞盆,因為這樣直接訪問實例變量破壞了封裝性,使代碼更脆弱。如果重寫了類方法+(BOOL)accessInstanceVariablesDirectly返回NO的話吓歇,那么會直接調用valueForUndefinedKey:
還沒有找到的話孽水,調用valueForUndefinedKey:
什么時候用@autoreleasepool
根據(jù)Apple的文檔,使用場景如下:
1.寫循環(huán)城看,循環(huán)里面包含了大量臨時創(chuàng)建的對象女气。(本文的例子,相冊析命,本地文件的遍歷就會產生比較多開銷較大的對象主卫,使用block來遍歷,在遍歷的時候會在內部創(chuàng)建自動釋放池來對對象及時釋放)
2.長時間在后臺運行的任務鹃愤。(如長時間運行在后臺的網(wǎng)絡服務)
97.github + xcode結合使用
特點:
分布式:可以將代碼提交到本地代碼庫簇搅,在確定后再更新到服務器上。
流程:
一般在開發(fā)中软吐,多人合作開發(fā)的時候瘩将,版本控制非常重要,所以一定要有穩(wěn)定的主分支Master凹耙,開發(fā)功能的分支developer姿现,預發(fā)布的分支release這三個重要分支。每次有新功能和需求的時候每個開發(fā)人員就從developer分支分別拉取項目開發(fā)肖抱,最后合并入developer备典,功能完成后就并入release,修改bug時在release分支操作意述,修復完成后分別并入Master和developer分支提佣,最后從Master分支拉取最終的代碼打包上傳APP Store
常用命令:
commit 將代碼提交到本地代碼庫
push 將本地代碼庫提交到服務器
pull 將服務器代碼更新到本地上
merge 分之合并
viewController的生命周期
初始化:
1.initWithNibName(通過代碼調用,如present荤崇,pushNavigation)
2.initWithCoder(如果使用 storyboard 調用VC拌屏,VC這個時候是放在storyboard中),然后調用 awakeFromNib
如果view為 nil ?
loadView (系統(tǒng)通過代碼方式創(chuàng)建一個空的view),如果自己覆蓋术荤,則需要同樣按照系統(tǒng)的方法去寫
UIView *view = [[UIView alloc]initWithFrame:[UIScreen mainScreen].bounds];
self.view = view;
不要使用 [super loadView]
viewDidLoad:view加載完畢
viewWillAppear:控制器的view將要顯示
viewWillLayoutSubviews:控制器的view將要布局子控件
viewDidLayoutSubviews:控制器的view布局子控件完成
這期間系統(tǒng)可能會多次調用viewWillLayoutSubviews 倚喂、 ? ?viewDidLayoutSubviews 倆個方法
viewDidAppear:控制器的view完全顯示
viewWillDisappear:控制器的view即將消失的時候
viewDidDisappear:控制器的view完全消失的時候
loadView viewDidLoad
loadView方法在控制器的view為Nil的時候會調用,若控制器有關聯(lián)的 Xib 文件瓣戚,該方法會從 Xib 文件中加載 view端圈;如果沒有,則創(chuàng)建空白 UIView 對象子库。
如果用storyboard初始化控制器,就不用調用loadview方法了枫笛。如果重寫這個方法給控制器創(chuàng)建view則這個view必須是一個單例,而且不能被其他的控制器使用.并且不可以調用super。
不建議使用loadview,可以根據(jù)自己的需要在storyboard或者viewdidload中創(chuàng)建自己需要的view給控制器刚照,如果使用 Interface Builder 創(chuàng)建 view,則務必不要重寫該方法喧兄。
viewDidlLoad :view 被加載到內存后調用无畔,不管什么情況都會被調用啊楚,用于視圖的初始化。
集合遍歷方法
1.對于數(shù)據(jù)量比較大浑彰,或者在便利過程中會產生一些消耗較大的臨時恭理,使用block的形式遍歷更好,因為使用多線程的方式郭变,并且內部會自動創(chuàng)建一個autoreleasepool颜价,對臨時創(chuàng)建的對象及時釋放。
2.一般的遍歷诉濒,如果不需要使用到下標周伦,那么使用for in的方式更直觀效率也高。
3.對于block的數(shù)組方式未荒,除了NSEnumerationConcurrent這種會在子線程內遍歷专挪,其余都是在主線程遍歷。NSEnumerationConcurrent使用了GCD的group原理片排,當遍歷完成寨腔,返回主線程
常量
define 宏:只是在預處理器里進行文本替換,不能聲明類型率寡,會多次地分配內存迫卢。除了定義常量,還可以定義函數(shù)宏
#define MIN(A,B) A < B ? A : B
const 常量:只分配一次內存
修飾局部變量
static const (內存分配在靜態(tài)區(qū)冶共,在運行周期中保持一份)
聲明全局常量:
extern NSString *const kName?
UIKIT_EXTERN
FOUNDATION_EXPORT
autorelease 對象釋放
1.autorelease 本質上就是延遲調用 release乾蛤,autorelease pool,其實這個pool本質上是一個stack比默,扔到pool中的對象等價于入棧
2.默認下幻捏,對象會在當前runloop迭代結束的時候釋放。
viewDidAppear 調用之前命咐,NSAutoreleasePool會在當前runLoop迭代結束的時候被銷毀篡九,向池中的對象發(fā)送release消息,并且pop彈出棧中醋奠。
3.手動指定 @autoreleasepool {}榛臼,當出了@autoreleasepool {}的作用域時,當前autoreleasepool被drain窜司,其中的autoreleased對象被release
4.對于每一個Runloop沛善,系統(tǒng)會隱式創(chuàng)建一個Autorelease pool(自然會有多個Autorelease pool),這樣所有的release pool會構成一個象CallStack一樣的一個棧式結構塞祈,在每一個Runloop結束時金刁,當前棧頂?shù)腁utorelease pool會被銷毀,這樣這個pool里的每個Object會被release。
- (void)viewDidLoad {
[superviewDidLoad];
//????@autoreleasepool?{
//????????NSString?*string?=?[NSString?stringWithFormat:@"leichunfeng"];//對象創(chuàng)建時計數(shù)器+1尤蛮,有變量指向它媳友,+1,計數(shù)器為= 2
//????????string_weak_?=?string;
//????}
//出了池的作用域产捞,池被釋放醇锚,對象計數(shù)器 - 1,局部變量為nil坯临,計數(shù)器-1焊唬,這時候對象被釋放
//????NSString?*string?=?nil;
//????@autoreleasepool?{
//????????string?=?[NSString?stringWithFormat:@"leichunfeng"];
//????????string_weak_?=?string;
//????}
出了池的作用域,池被釋放看靠,對象計數(shù)器 - 1赶促,局部變量這個時候還存,所以只有在viewdidload結束的時候衷笋,才會置nil芳杏,計數(shù)器-1,這時候對象被釋放辟宗,所以對象在viewdidload內還存在爵赵,在viewwillappear才會是nil
NSLog(@"string:?%@",?string_weak_);
}
block對象就是一個結構體,里面有isa指針指向自己的類(global malloc stack)泊脐,有desc結構體描述block的信息空幻,引用到的__block變量,最重要的block結構體有一個函數(shù)指針容客,指向block代碼塊秕铛。
KVO,NSNotification Delegate都是同步發(fā)送消息的