流水不腐,戶樞不蠹

-22 viewDidAppear 不調用

如果是直接把ViewController的view 通過addSubview添加到另一個View,則不會調用viewDidAppear,你需要手動發送viewDidAppear給這個View Controller。

當我向一個UINavigationController壓入一個視圖控制器的時候,
         1.    什麼時候會觸發viewWillAppear和viewDidAppear?
         2.    什麼導致了觸發viewWillAppear和viewDidAppear失敗?
【答】:
    當你調用pushViewController:animated把一個視圖控制器壓入UINavigationController的時候,UINavigationController會自動調用這些方法。相似的,當你tabs時,UITabBarController會直接調用這些方法,當你使用presentModalViewController時也會調用方法。當一個視圖控制器的視圖被添加到一個window中時也會調用這些方法。我在這些情況下沒有遇到過這些方法調用失敗的情況。

    記住,這些方法只在這些特定的情況下控制器pushed或presented的時候被調用。在其它的情況下不會被調用,比如你添加你的視圖控制器的視圖作爲一個視圖的子視圖而不是作爲window的子視圖。蘋果官方文檔說視圖控制器僅用於全屏顯示的視圖,典型的是使用上面提到的方法。可以忽略蘋果的建議使一個視圖控制器關聯另一個視圖控制的的視圖作爲子視圖,但是你需要在作爲容器的視圖控制器中手動的調用嵌套控制器的viewWillAppear和viewDidAppear。

https://blog.csdn.net/hherima/article/details/49514191

 

-21 iOS內存分配與分區

https://www.jianshu.com/p/7bbbe5d55440

  • 在iOS中,堆區的內存是應用程序共享的,堆中的內存分配是系統負責的;
  • 系統使用一個鏈表來維護所有已經分配的內存空間(系統僅僅紀錄,並不管理具體的內容);
  • 變量使用結束後,需要釋放內存,OC中是根據引用計數==0,就說明沒有任何變量使用該空間,那麼系統將直接收回;
  • 當一個app啓動後,代碼區,常量區,全局區大小已固定,因此指向這些區的指針不會產生崩潰性的錯誤。而堆區和棧區是時時刻刻變化的(堆的創建銷燬,棧的彈入彈出),所以當使用一個指針指向這兩個區裏面的內存時,一定要注意內存是否已經被釋放,否則會產生程序崩潰(也即是野指針報錯)。

-20 block

https://blog.csdn.net/wks_lovewei/article/details/80563106  iOS底層原理總結 - 探尋block的本質

https://blog.csdn.net/Deft_MKJing/article/details/53143076  iOS Block源碼分析系列

-19 C語言中static變量詳解

https://www.jianshu.com/p/3e819d731c79

1.全局靜態變量
  在全局變量之前加上關鍵字static,全局變量就被定義成爲一個全局靜態變量。
  1)內存中的位置:靜態存儲區(靜態存儲區在整個程序運行期間都存在)
  2)初始化:未經初始化的全局靜態變量會被程序自動初始化爲0(自動對象的值是           任意的,除非他被顯示初始化)
  3)作用域:全局靜態變量在聲明他的文件之外是不可見的。準確地講從定義之處開始到文件結尾。
  定義全局靜態變量的好處:
  <1>不會被其他文件所訪問,修改
  <2>其他文件中可以使用相同名字的變量,不會發生衝突。
 
2.局部靜態變量
在局部變量之前加上關鍵字static,局部變量就被定義成爲一個局部靜態變量。
  1)內存中的位置:靜態存儲區
  2)初始化:未經初始化的局部靜態變量會被程序自動初始化爲0(自動對象的值是任意的,除非他被顯示初始化)
  3)作用域:作用域仍爲局部作用域,當定義它的函數或者語句塊結束的時候,作用域隨之結束。
  注:當static用來修飾局部變量的時候,它就改變了局部變量的存儲位置,從原來的棧中存放改爲靜態存儲區。但是局部靜態變量在離開作用域之後,並沒有被銷燬,而是仍然駐留在內存當中,直到程序結束,只不過我們不能再對他進行訪問。
  當static用來修飾全局變量的時候,它就改變了全局變量的作用域(在聲明他的文件之外是不可見的),但是沒有改變它的存放位置,還是在靜態存儲區中。
 
3.Static修飾的函數
 在函數的返回類型前加上關鍵字static,函數就被定義成爲靜態函數。
函數的定義和聲明默認情況下是extern的,但靜態函數只是在聲明他的文件中可見,不能被其他文件所用。
 
 定義靜態函數的好處:
  <1> 其他文件中可以定義相同名字的函數,不會發生衝突 
   <2> 靜態函數不能被其他文件所用。
 存儲說明符auto,register,extern,static,對應兩種存儲期:自動存儲期和靜態存儲期。
  auto和register對應自動存儲期。具有自動存儲期的變量在進入聲明該變量的程序塊時被建立,它在該程序塊活動時存在,退出該程序塊時撤銷。
  關鍵字extern和static用來說明具有靜態存儲期的變量和函數。用static聲明的局部變量具有靜態存儲持續期(static storage duration),或靜態範圍(static extent)。雖然他的值在函數調用之間保持有效,但是其名字的可視性仍限制在其局部域內。靜態局部對象在程序執行到該對象的聲明處時被首次初始化。
 

-18 iOS OC中分類Category實現原理

https://blog.csdn.net/shihuboke/article/details/79214171

https://tech.meituan.com/DiveIntoCategory.html

-17

參考:https://blog.csdn.net/Hello_Hwc/article/details/80094632

一、__bridge

進行OC指針和CF指針之間的轉換,不涉及對象所有權轉換。

那麼,什麼叫做對象的所有權轉換呢?再理解之前記住兩點:

Foundation對象是由ARC管理的(這裏不考慮MRC的情況),你不需要手動retain和release。

Core Foundation的指針是需要手動管理生命週期。

舉例:OC -> CF,所有權在Foundation,不需要手動管理

NSString * str = [NSString stringWithFormat:@"%ld",random()];

CFStringRef cf_str = (__bridge CFStringRef)str;

NSLog(@"%ld",(long)CFStringGetLength(cf_str));

舉例:CF -> OC,所有權在CF,需要手動管理內存

 

CFStringRef cf_str = CFStringCreateWithFormat (NULL, NULL, CFSTR("%d"), rand());

NSString * str = (__bridge NSString *)cf_str;

NSLog(@"%ld",(long)str.length);

//這一行很有必要,不然會內存泄漏

CFRelease(cf_str);

二、__bridge_retained

將一個OC指針轉換爲一個CF指針,同時移交所有權,意味着你需要手動調用CFRelease來釋放這個指針。這個關鍵字等價於CFBridgingRetain函數。

舉例:

NSString * str = [NSString stringWithFormat:@"%ld",random()];

CFStringRef cf_str = (__bridge_retained CFStringRef)str;

NSLog(@"%ld",(long)CFStringGetLength(cf_str));

CFRelease(cf_str);

 

三、__bridge_transfer

      將一個CF指針轉換爲OC指針,同時移交所有權,ARC負責管理這個OC指針的生命週期。這個關鍵字等價於CFBridgingRelease

舉例:

CFStringRef cf_str = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), rand());

NSString * str = (__bridge_transfer  NSString *)cf_str;

NSLog(@"%ld",(long)str.length);

四、總結一句話,所有權在Foundation,則不需要手動管理內存;所有權在CF,需要調用CFRetain/CFRelease來管理內存。

 

-16  64bit 's  tips

1 數據類型的變化:       

       數據類型裏面,NSInteger在32位時等同於int,在64位時等同於long,而這個數據結構使用非常廣,非常多不規範的時候會直接和int替換使用,在32位是毫無問題,但在64位時。這就是隱患了。CGFloat也有相同的問題,所以代碼的檢查改動必須細緻。

        至於對齊,假設使用了偏移量來訪問struct的項,那麼須要認真細緻的檢查,其餘的還算好。當然假設你用了malloc,那麼也請檢查一下分配的內存大小。建議是多使用sizeof來幫助計算。

        還有,針對存儲的文件。比方存儲在iCloud上的文件。你無法確定是一個32位應用還是64位的應用會去訪問。那麼請一定把數據內容的解釋寫成一模一樣。

2 方法調用上的變化

3 彙編的不同,  由於是不同的指令集。彙編當然會不同。只是我們一般的應用不會用到彙編,所以這一項比較少遇到。

4  第三方庫, 我們項目中使用的第三方庫肯定須要支持64位系統。否則還是白搭。 所以大家在升級時須要檢查自己使用的第三方的庫。看是否已經有64位的版本號出現了。

-15 二叉樹各種計算公式總結

1.n個節點的二叉樹一共有((2n)!)/(n! * (n+1)!)種 
2.n層二叉樹的第n層最多爲2^(n-1)個 
3.二叉樹節點計算公式 N = n0+n1+n2,度爲0的葉子節點比度爲2的節點數多一個。N=1*n1+2*n2+1 
4.對任何一棵二叉樹T,如果其終端節點數爲n0,度爲2的節點數爲n2,則n0=n2+1 
5.具有n個節點的完全二叉樹的深度爲log2(n) + 1
6 二叉樹類型 https://www.cnblogs.com/love-yh/p/7423301.html
原文:https://blog.csdn.net/qq_33401691/article/details/78021446 
 

-14 hash 衝突

 https://www.jianshu.com/p/14a5089e0456

-13 NSRunLoop Observers

       

 kCFRunLoopEntry:                  NSLog(@"進入");

kCFRunLoopBeforeTimers:     NSLog(@"即將處理Timer事件");

kCFRunLoopBeforeSources:   NSLog(@"即將處理Source事件");

kCFRunLoopBeforeWaiting:    NSLog(@"即將休眠");

kCFRunLoopAfterWaiting:       NSLog(@"被喚醒");

kCFRunLoopExit:                      NSLog(@"退出RunLoop"); 


 

-12 靜態庫(Static Library)和動態框架(Dynamic Framework)

https://blog.csdn.net/u012581760/article/details/53008454

https://www.cnblogs.com/codingmengmeng/p/6046481.html

https://blog.csdn.net/houyichaochao/article/details/80857632

https://www.cnblogs.com/junhuawang/p/7598236.html

-11 SQLite多線程安全

    三種模式。默認

   https://www.jianshu.com/p/6c671b3f409e

-10 iOS 關於離屏渲染的理解 以及解決方案

        https://www.jianshu.com/p/cff0d1b3c915  

        https://www.jianshu.com/p/f247f8c13b32

-9 image 優化之 —— image copy 字節對齊

       https://www.jianshu.com/p/9467b424f172

-8 [[UIScreen mainScreen] scale]

       [[UIScreen mainScreen] scale]是計算屏幕分辨率的

  • [[UIScreen main] scale] == 1; //代表320 x 480 的分辨率(就是iphone4之前的設備,非Retain屏幕)
  • [[UIScreen main] scale] == 2; //代表640 x 960 的分辨率(Retain屏幕)
  • [[UIScreen main] scale] == 3; //代表1242 x 2208 的分辨率

-7 AVFundation視頻錄製播放

-6  @synchronized 

https://www.jianshu.com/p/68d1b867af8d

-5 Toll-Free Bridging

https://blog.csdn.net/Hello_Hwc/article/details/80094632

-4 iOS App 簽名的原理

http://blog.cnbang.net/tech/3386/

https://mp.weixin.qq.com/s/PC9Bb0maBIocvLdrQZd95Q

-3 watchOS

 https://www.jianshu.com/p/02d6f80ac803

https://www.jianshu.com/p/ef1fb33fe2e6

 

-2 WebView與JS的交互

https://www.jianshu.com/p/0042d8eb67c0

-1 圖片優化 解碼

   http://www.open-open.com/lib/view/open1495626153650.html#articleHeader10  如何打造易擴展的高性能圖片組件

 http://www.cocoachina.com/ios/20180626/23933.html  iOS的5種圖片縮略技術以及性能探討

https://mp.weixin.qq.com/s/KsZyvwIpuTjOVCuWDo7LYw  iOS高效圖片 IO 框架是如何煉成的

0 block與property

  地址: http://www.cocoachina.com/ios/20170503/19165.html
 

1. weak 與 assgin

@property (nonatomic, assign, readwrite) id delegate;

聲明一個delegate,那麼即便delegate指向的對象銷燬了,delegate中依然會保存之前對象的地址

即,delegate成爲了一個野指針

@property (nonatomic, weak, readwrite) id delegate;
 

而使用weak,則不會有上述問題,當delegate指向的對象銷燬後,delegate = nil。

擴展:

(1)assign “設置方法”只會招待針對“純量類型”(scalar type,例如CGFloat或NSInteger等)的簡單賦值操作。 
strong 此特質表明該屬性定義了一個擁有關係(owning relationship)。爲這種屬性設置新值時,設置方法會先保留新值,再釋放舊值,然後再將新值設置上去。 
(2)weak 此特質表明該屬性定義了一種非擁有關係(no owning relationship),爲這種屬性添加新值時,設置方法即不保留新值,也不保留舊值。此特質同assign類似,然而在改改所指的對象遭到摧毀時,屬性值也會清空(nilout). 
(3)unsafe_unretained 
看名字就知道了 ,不安全 不增加引用計數 
NSString* str1 = @"123"; 
unsafe_unretianed NSString* str2 = str1; 

[str1 release]; 
str2也跟着消失的無影無蹤了,指針的地址空間都被清空了,和C++的引用很相似,別名。
 


 

2.block 的三種類型 實例

@interface Test : NSObject{

    int  xx ;

}

@property (copy) BlockA  block2;

@property (copy) NSString  *  test;

@property (assign) int  z ;

- (void)testFuc;

 

@end


 

BlockA block3 = ^{

    int  xx = 200;

    NSLog(@" 全局   %d", xx);

};

 

@implementation Test

- (void)testFuc{

    xx =10;

    int yy = 11;

    __block int t = 11;

    

    self.test = @"22222";

    //  stack 棧  --------------------

    void(^block1)(void) = ^{

         xx = 100;

        NSLog(@"棧 %d",xx);

        self.test = @"90900990090990990";

        // yy = 100;   //會編譯error

    };

   

    block1();

    

    

    self.z = 4001;

 

    __weak typeof(self) wSelf = self;

    // 堆上的  --------------------

    self.block2 = ^{

        __strong typeof(wSelf) sSelf = wSelf;

        xx = 200;          //循環引用

        NSLog(@"堆上的  %d", xx); //循環引用

        sSelf->xx = 201;   //這樣不會循環引用

        NSLog(@"堆上的  %d",  sSelf->xx);

        

        //  yy = 90;  //  會編譯 error

        t = 100;      // 正確     

        sSelf.z = 400;

       NSLog(@"堆上的  %d", sSelf.z);

        

    };

    

    self.block2();

   

    //global  全局  --------------------


 

    block3();

}

@end


 

擴展:

在Objective-C語言中,一共有3種類型的block:

1._NSConcreteGlobalBlock 全局的靜態block,不會訪問任何外部變量。

2._NSConcreteStackBlock 保存在棧中的block,當函數返回時會被銷燬。

3._NSConcreteMallocBlock 保存在堆中的block,當引用計數爲0時會被銷燬。


 


 

3 線程死鎖

(1)串行隊列

 dispatch_queue_t concurrentQueue= dispatch_queue_create("my.queue", DISPATCH_QUEUE_SERIAL);

    NSLog(@"1");

     dispatch_async(concurrentQueue, ^(){    

        NSLog(@"4");

        dispatch_sync(concurrentQueue, ^(){

            NSLog(@"4.1");

        });

     });

    NSLog(@"5");
 


 

輸出:1 ,5,4   ,然後死鎖

 dispatch_queue_t concurrentQueue= dispatch_queue_create("my.queue", DISPATCH_QUEUE_SERIAL);// 串行隊列

    NSLog(@"1");

     dispatch_sync(concurrentQueue, ^(){    

        NSLog(@"4");

        dispatch_sync(concurrentQueue, ^(){

            NSLog(@"4.1");

        });

     });

    NSLog(@"5");
 


 

輸出:1 ,4    ,然後死鎖

(2)並行隊列

 dispatch_queue_t concurrentQueue= dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);// 並行隊列


 

此時不會死鎖。

(3)主線程是串行的

所以,也會死鎖

 

 擴展:http://www.jianshu.com/p/44369c02b62a


 

(4)死鎖分析

dispatch_queue_t queue =dispatch_queue_create("abc", DISPATCH_QUEUE_SERIAL);

dispatch_sync(queue,^{//taskA

    //dosomething

   dispatch_sync(queue, ^{//taskB

       //啥也幹不了

    });

});

 

dispatch_sync函數用於將一個block(任務)提交到隊列中同步執行,直到block執行完後,這個函數纔會返回。queue是一個串行隊列,如果先後加入兩個任務,taskAtaskB, 那麼只有taskA執行完之後taskB才能執行。如果taskB是在taskA中加進隊列的,那麼它們依然遵守先進先出原則,即taskA執行完之後taskB才執行,也就是taskB在等待taskA完成。但是因爲dispatch_sync的同步特性,taskB執行不完taskA就不算完成,即taskA在等待taskB的完成,這樣就發生了死鎖。

 

根據上面那份代碼,我們就可以理解下面的代碼爲什麼會阻塞主線程了。

 

dispatch_queue_t mainQueue = dispatch_get_main_queue();

dispatch_sync(mainQueue, ^{

   NSLog(@"hello");

});

mainQueue是系統創建的,在執行上面的代碼之前就已經加進去了很多任務

 

dispatch_queue_t queue = dispatch_queue_create("Main", DISPATCH_QUEUE_SERIAL);

dispatch_sync(queue, ^{

    //Task A

});

...

dispatch_sync(queue, ^{

    //Task N

});

在這N個任務裏有一個任務是這樣的:

 

dispatch_sync(queue, ^{

   dispatch_queue_t mainQueue = dispatch_get_main_queue();

   dispatch_sync(mainQueue, ^{

       NSLog(@"hello");

    });

});

所以,發生死鎖就是必然的了。


 

 

4   hittest ,subViews

如果視圖是從nib中加載的,我們應該首先實現initWithCode:因爲nib中的對象實例將存儲爲歸檔對象。(某一個view設置爲自定義的子view)


 

遍歷UIView子視圖,找出按鈕控件,如果點擊在範圍內則返回當前控件


- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
 

  for (UIView *tmpView in self.subviews )
    {
        if(tmpView.userInteractionEnabled &&[tmpView isMemberOfClass:[UIButton class]])
        {
            if(CGRectContainsPoint(tmpView.frame,point)) {
                return tmpView;
            }
        }
    }
    return nil;
}
 

class  NSView  中  @property (copy) NSArray<__kindof NSView *> *subviews;


 

5 runloop and autorelease


 

參考《黑幕背後的Autorelease》

 __weak id reference = nil;
- (void)viewDidLoad {
    [super viewDidLoad];
    NSString *str = [NSString stringWithFormat:@"sunnyxx"];
    // str是一個autorelease對象,設置一個weak的引用來觀察它
    reference = str;
}
- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    NSLog(@"%@", reference); //Console: sunnyxx
}
- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    NSLog(@"%@", reference); // Console: (null)
}
這個實驗同時也證明了viewDidLoadviewWillAppear是在同一個runloop調用的,而viewDidAppear是在之後的某個runloop調用的。
由於這個vc在loadView之後便add到了window層級上,所以viewDidLoad和viewWillAppear是在同一個runloop調用的,因此在viewWillAppear中,這個autorelease的變量依然有值。


當然,我們也可以手動干預Autorelease對象的釋放時機:


- (void)viewDidLoad {
    [super viewDidLoad];
    @autoreleasepool {
        NSString *str = [NSStringstringWithFormat:@"sunnyxx"];
    }
    NSLog(@"%@", str); // Console: (null)
}



 

6  autoreleasepool

使用容器的block版本的枚舉器時,內部會自動添加一個AutoreleasePool:


[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
   // 這裏被一個局部@autoreleasepool包圍着
}];
 在普通for循環和for in循環中沒有,所以,還是新版的block版本枚舉器更加方便。for循環中遍歷產生大量autorelease變量時,就需要手加局部AutoreleasePool咯。

7  nsrunloop 的使用

NSURLConnection ::


 

   NSMutableURLRequest* request = [[NSMutableURLRequest alloc]initWithURL:self.URL                                                                                   cachePolicy:NSURLRequestReloadIgnoringCacheData

                                                         timeoutInterval:self.timeoutInterval];

    [request setHTTPMethod:@"GET"];

    

    self.connection=[[NSURLConnection alloc] initWithRequest:request

                                                  delegate:self

                                           startImmediately:NO];

    [self.connection    scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];

    [self.connection  start];

 GCD::

  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^(){

       [downloader start];

       NSLog(@"current worker thread: %@", [NSThread currentThread]);

       [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate  distantFuture]];

       NSLog(@"exit worker thread");

    });

 

 

 

 8 Cocoa和CoreFoundation定義的標準模式:

 
NSDefaultRunLoopMode:默認的運行模式,用於大部分操作,除了NSConnection對象事件。
NSConnectionReplyMode:用來監控NSConnection對象的回覆的,很少能夠用到。
NSModalPanelRunLoopMode:用於標明和Mode Panel相關的事件。
NSEventTrackingRunLoopMode:用於跟蹤觸摸事件觸發的模式(例如UIScrollView上下滾動)。
NSRunLoopCommonModes:是一個模式集合,當綁定一個事件源到這個模式集合的時候就相當於綁定到了集合內的每一個模式。

        

      Cocoa應用默認包含Default、Panel、Event Tracking模式,Core Foundation只包含Default模式,我們可以通過CFRunLoopAddCommonMode添加模式。
 

 

9 CoreFoundation 裏面關於 RunLoop 有5個類


   CFRunLoopRef
   CFRunLoopModeRef
   CFRunLoopSourceRef
   CFRunLoopTimerRef
   CFRunLoopObserverRef


其中 CFRunLoopModeRef 類並沒有對外暴露,只是通過 CFRunLoopRef 的接口進行了封裝。

 

10 RunLoop 的內部邏輯

 

1.   通知察者NSRunloop

2.   如果有Timer即將觸發時,通知察者

3.   如果有非PortInput Sourc即將e發時,通知察者

4.   PortInputSource事件源

5.   如果基於PortInput Source事件源即將觸發時,立即事件,跳到步9

6.   通知察者當前程將入休眠狀

7.   入休眠狀直到有以下事件生:基於PortInput Source被觸Timer被觸Run Loop運行時間到了時間Run Loop

8.   通知察者程將要被

9.   處理被觸發的事件:如果是用戶自定義的TimerTimer事件後重新啓Run Loop進入步驟2、如果程被醒又沒有到時間則進入步2、如果是其他Input Source事件源有事件生,直接個事件

10. 到達此步驟說Run Loop運行時間到期,或者是非TimerInput Source事件被理後,RunLoop將要退出,退出前通知察者程已退出

Source 0:

        處理如UIEvent,CFSocket這樣的事件 (觸摸事件、按鈕點擊事件)。

        使用時,你需要先調用 CFRunLoopSourceSignal(source),將這個 Source 標記爲待處理 signal 狀態,然後手動調 CFRunLoopWakeUp(runloop) 來喚醒 RunLoop,讓其處理這個事件。

Source 1:

       基於Port的,通過內核和其他線程通信,接收分發系統事件 Mach port驅動,CFMachport,CFMessagePort。 (觸摸硬件,通過 Source1 接收和分發系統事件到 Source0 處理)

 

 

 

 

 

 

11.runloop、autorelease pool以及線程之間的關係

 

        每個線程(包含主線程)都有一個Runloop

       對於每一個Runloop,系統會隱式創建一個Autorelease pool,這樣所有的release pool會構成一個像callstack一樣的一個棧式結構,在每一個Runloop結束時,當前棧頂的Autorelease pool會被銷燬,這樣這個pool裏的每個Object會被release

12 dispatch_onece_t  單例

+ (AccountManager *)sharedManager

{

  staticAccountManager *sharedAccountManagerInstance = nil;  // 靜態變量 ,只執行一次。從第二次後,每次進這個方法後,這句都不執行。

  staticdispatch_once_t predicate;            // 靜態變量 ,只執行一次。從第二次後,每次進這個方法後,這句都不執行。

 

  dispatch_once(&predicate, ^{     

      sharedAccountManagerInstance= [[self alloc] init]; 

  });

   return   sharedAccountManagerInstance;

}

 

dispatch_once  函數會執行多次,但是 block只執行一次。

13assign、strong、weak, copy的區別

 

    assign “設置方法” 只會執行鍼對“純量”的簡單賦值操作。

  strong  此特質表明該屬性定義了一種“擁有關係”。爲這種屬性設置新值時,設置方法會先保留新值,並釋放舊值,然後再將新值設置上去。

  weak 此特質表明該屬性定義了一種“非擁有關係”。爲這種屬性設置新值時,設置方法既不保留新值,也不釋放舊值。此特質同assign類似,然而在屬性所指的對象遭到推毀時,屬性值也會清空

  unsafe_unretained 此特質的語義和assign相同,但是它適用於“對象類型”,該特質表達一種“非擁有關係”,當目標對象遭到推毀時,屬性值不會自動清空,這一點與weak有區別

 copy此特質所表達的所屬關係與strong類似。然而設置方法並不保留新值,而是設置方法並不保留新值,而是將其“拷貝”。

 

 

 

    當屬性類型爲NSString*時,經常用此特質來保護其封裝性,因爲傳遞給設置方法的新值有可能指向一個NSMutableString類的實例。這個類是NSString的子類,表示一種可以修改其值的字符串,此時若是不拷貝字符串,那麼設置完屬性之後,字符串的值就可能會在對象不知情的情況下遭人更改。所以,這時就要拷貝一份“不可變”的字符串,確保對象中的字符串值不會無意間變動。只要實現屬性所用的對象是“可變的”,就應該在設置新屬性值時拷貝一份。

 

14 內存 問題

@autoreleasepool {   

 NSString *str = [[NSString alloc] init];   

  [str  retain];    

  [str  retain];     

  str =@"jxl";   

  [str  release];   

  [str  release];   

  [str  release];

}

1.內存泄露 2.指向常量區的對象不能release。

指針變量str原本指向一塊開闢的堆區空間,但是經過重新給str賦值,str的指向發生了變化,由原來指向堆區空間,到指向常量區。

常量區的變量根本不需要釋放,這就導致了原來開闢的堆區空間沒有釋放,照成內存泄露。

 

 

15 . 分別寫一個setter方法用於完成@property (nonatomic,retain)NSString *name和@property(nonatomic,copy) NSString *name

 

retain屬性的setter方法是保留新值並釋放舊值,然後更新實例變量,令其指向新值。順序很重要。假如還未保留新值就先把舊值釋放了,而且兩個值又指向同一個對象,先執行的release操作就可能導致系統將此對象永久回收。

 

-(void)setName:(NSString *)name

{

   [name  retain];

   [_name  release];

   _name =  name;

}

-(void)setName:(NSString *)name

{

   

   [_name  release];

   _name =  [name copy];

}

 

16.  GCD  dispatch_barrier_async

 

 

    dispatch_queue_t concurrentQueue =dispatch_queue_create("my.concurrent.queue",DISPATCH_QUEUE_CONCURRENT);

    dispatch_async(concurrentQueue, ^(){

        NSLog(@"dispatch-1");

    });

    dispatch_async(concurrentQueue, ^(){

        NSLog(@"dispatch-2");

    });

    

    dispatch_barrier_async(concurrentQueue, ^(){

           NSLog(@"dispatch-barrier");

      

    });

    

    dispatch_async(concurrentQueue, ^(){

        NSLog(@"dispatch-3");

    });

    dispatch_async(concurrentQueue, ^(){

        NSLog(@"dispatch-4");

    });

 

 

17 .  dispatch_group_t 

  

  dispatch_group_tgroup = dispatch_group_create();   // 某個任務放進 group

  dispatch_group_async(group,dispatch_get_global_queue(0, 0), ^{   

  // 任務代碼1  

 });

  dispatch_group_async(group,dispatch_get_global_queue(0, 0), ^{    

 // 任務代碼2  

 });

  dispatch_group_notify(group,dispatch_get_main_queue(), ^{    

 // 任務全部完成處理     NSLog(@"isover"); 

  });

 

  dispatch_async(dispatch_get_global_queue(0, 0), ^{  

   for (inti = 0; i < 3; i ++)     {     

  dispatch_group_enter(group);       // 任務代碼i 假定任務 是異步執行block回調     

  // block回調執行     

 dispatch_group_leave(group);      // block回調執行  

  }  

 }); 

  dispatch_group_wait(group,DISPATCH_TIME_FOREVER);   dispatch_async(dispatch_get_main_queue(), ^{ 

    // 主線程處理  

 });

參考:

把一組任務提交到隊列中,這些隊列可以不相關,然後堅挺這組任務完成的事件。

幾個用到的函數

1、dispatch_group_create創建一個調度任務組

func dispatch_group_create() -> dispatch_group_t!

 

 

2、dispatch_group_async 把一個任務異步提交到任務組裏

func dispatch_group_async(_ group: dispatch_group_t!,   _queue: dispatch_queue_t!, _ block: dispatch_block_t!)

     

  參數: group 提交到的任務組,這個任務組的對象會一直持續到任務組執行完畢

     queue 提交到的隊列,任務組裏不同任務的隊列可以不同

     block 提交的任務

 

3、dispatch_group_enter/dispatch_group_leave

funcdispatch_group_enter(_ group: dispatch_group_t!)func dispatch_group_leave(_group: dispatch_group_t!)

這兩個方法顯示的講任務組中的任務未執行完畢的任務數目加減1,這種方式用在不使用dispatch_group_async來提交任務,注意:這兩個函數要配合使用,有enter要有leave,這樣才能保證功能完整實現。也可以用這對函數來讓一個閉包關聯多個Group

 

 

4、dispatch_group_notify 用來監聽任務組事件的執行完畢

funcdispatch_group_notify(_ group: dispatch_group_t!,            

                       _ queue:dispatch_queue_t!,     

                        _block: dispatch_block_t!)

參數: group監聽的任務組

queue 執行完畢的這個閉包所在的隊列

block 執行完畢所響應的任務

5、dispatch_group_wait 設置等待時間,在等待時間結束後,如果還沒有執行完任務組,則返回。返回0代表執行成功,非0則執行失敗

long dispatch_group_wait (dispatch_group_t group, dispatch_time_t timeout );

   

 參考:https://www.jianshu.com/p/228403206664  

 

 

18  定時器

1).dispatch_source_t

NSTimeIntervalperiod = 1.0; //設置時間間隔

dispatch_queue_tqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

 

dispatch_source_t_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);

 

dispatch_source_set_timer(_timer,dispatch_walltime(NULL, 0), period * NSEC_PER_SEC, 0); //每秒執行

dispatch_source_set_event_handler(_timer,^{

   //在這裏執行事件

});

dispatch_resume(_timer);

 

2)dispatch_after 執行一次

doubledelayInSeconds = 2.0;

 

dispatch_time_tpopTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); 

 

dispatch_after(popTime,dispatch_get_main_queue(), ^(void){ 

   //執行事件

});

 

3) NSTimer

(1)默認加入runloop

 

NSTimer*timer =  [NSTimer   scheduledTimerWithTimeInterval:1.0 

  target:self 

  selector:@selector(action:) 

  userInfo:nilrepeats:NO];

 

(2)必須加入runloop

 

 

NSTimer*timer = [NSTimer  timerWithTimeInterval:5

 target:self 

selector:@selector(timerAction) 

userInfo:nil 

repeats:YES];

 

[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

 

 

4)擴展:

 

 

timer是不一定準時的,是有可能被delay的,每次間隔的時間是不一定一樣的。

 

 

Arepeating timer reschedules itself automatically based on the scheduled firingtime, not the actual firing time.

Forexample, if a timer is scheduled to fire at a particular time and every 5seconds after that, the scheduled 

firingtime will always fall on the original 5 second time intervals, even if theactual firing time gets delayed. 

If thefiring time is delayed so much that it misses one or more of the scheduledfiring times, the timer is fired 

onlyonce for the missed time period. After firing for the missed period, the timeris rescheduled for the next 

scheduledfiring time. 

簡單解讀一下:就是說一個repeat的timer,它在創建的時候就把每次的執行時間算好了,而不是真正啓動的時候

才計算下次的執行時間。舉個例子,假如一個timer在一個特定的時間t激活,然後以間隔5秒的時間重複執行。那麼

它的執行操作的時間就應該爲t, t+5, t+10,... 假如它被延遲了,

例如,實際上timer在t+2的時候才啓動,那麼它下次執行的時間還是t+5,而並不是t+2+5,如果很不幸地

在t+5還沒有啓動,那麼它理應該在t執行的操作就跟下一次t+5的操作合爲一個了。

至於爲什麼會延遲呢,這就跟當前線程的操作有關,因爲timer是同步交付的,所以假如當前線程在執行很複雜

的運算時,那必須等待運算的完成才能調用timer,這就導致了timer的延遲。

 

 

5)例子:

 

 

//這裏創建timer以每隔1秒執行

 [NSTimerscheduledTimerWithTimeInterval:1 target:self selector:@selector(timerDone)userInfo:nil repeats:YES];

 //這裏在第3秒的時候模擬一個複雜運算

 [selfperformSelector:@selector(busyDone) withObject:nil afterDelay:3];

   

-(void)busyDone

{

   //這裏模擬線程複雜的運算

  for(NSInteger i = 0; i< 0xffffffff;i++){

     

   }

  NSLog(@"BusgDone");

}

 

 

-(void)timerDone

{

  NSLog(@"Timer Run");

}

 

 

 6) .  CADisplayLink

// 屏幕刷新時調用

//CADisplayLink是一個能讓我們以和屏幕刷新率同步的頻率將特定的內容畫到屏幕上的定時器類。

CADisplayLink以特定模式註冊到runloop後,每當屏幕顯示內容刷新結束的時候,runloop就會向CADisplayLink指定的target

 

發送一次指定的selector消息, CADisplayLink類對應的selector就會被調用一次。所以通常情況下,按照iOS設備屏幕的刷新

率60次/秒

   // 延遲

   // iOS設備的屏幕刷新頻率是固定的,CADisplayLink在正常情況下會在每次刷新結束都被調用,精確度相當高。但如果調用

的方法比較耗時,超過了屏幕刷新週期,就會導致跳過若干次回調調用機會。

   // 如果CPU過於繁忙,無法保證屏幕60次/秒的刷新率,就會導致跳過若干次調用回調方法的機會,跳過次數取決CPU的忙碌程度。

   // 使用場景

   // 從原理上可以看出,CADisplayLink適合做界面的不停重繪,比如視頻播放的時候需要不停地獲取下一幀用於界面渲染。

   // 2.1創建出displaylink對象

  CADisplayLink *displyLink = [CADisplayLink displayLinkWithTarget:selfselector:@selector(reloop)];

   // 2.2 將該對象加入循環中

  [displyLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

   

   

   // 2.3再不需要時釋放(停止循環)

  [displyLink invalidate];

  displyLink = nil;

 

19  NULL  ,nil, Nil,NSNull

· NULL是宏,是對於C語言指針而使用的,表示空指針

· nil是宏,是對於Objective-C中的對象而使用的,表示對象爲空

· Nil是宏,是對於Objective-C中的類而使用的,表示類指向空

· NSNull是類類型,是用於表示空的佔位對象,與JS或者服務端的null類似的含意

 

20 NSRunLoop是消息機制的處理模式

NSRunLoop的作用在於有事情做的時候使的當前NSRunLoop的線程工作,沒有事情做讓當前NSRunLoop的線程休眠。

NSTimer默認添加到當前NSRunLoop中,也可以手動制定添加到自己新建的NSRunLoop

NSRunLoop就是一直在循環檢測,從線程start到線程end,檢測inputsource(如點擊,雙擊等操作)同步事件,檢測timesource同步事件,檢測到輸入源會執行處理函數,首先會產生通知,corefunction向線程添加runloop observers來監聽事件,意在監聽事件發生時來做處理。

在單線程的app中,不需要注意Run Loop,但不代表沒有。程序啓動時,系統已經在主線程中加入了Run Loop。它保證了我們的主線程在運行起來後,就處於一種等待的狀態(而不像一些命令行程序一樣運行一次就結束了),這個時候如果有接收到的事件(Timer的定時到了或是其他線程的消息),就會執行任務,否則就處於休眠狀態。

runloopmode是一個集合,包括監聽:事件源,定時器,以及需通知的runloop observers

模式包括:

         default模式:幾乎包括所有輸入源(NSConnection) NSDefaultRunLoopMode模式

         mode模式:處理modal panels

         connection模式:處理NSConnection事件,屬於系統內部,用戶基本不用

         event tracking模式:如組件拖動輸入源 UITrackingRunLoopModes 不處理定時事件

         common modes模式:NSRunLoopCommonModes 這是一組可配置的通用模式。將inputsources與該模式關聯則同時也將input sources與該組中的其它模式進行了關聯。

每次運行一個run loop,你指定(顯式或隱式)run loop的運行模式。當相應的模式傳遞給run loop時,只有與該模式對應的input sources才被監控並允許run loop對事件進行處理(與此類似,也只有與該模式對應的observers纔會被通知)

例:

1)在timertable同時執行情況,當拖動table時,runloop進入UITrackingRunLoopModes模式下,不會處理定時事件,此時timer不能處理,所以此時將timer加入到NSRunLoopCommonModes模式(addTimer forMode)

2)在scroll一個頁面時來鬆開,此時connection不會收到消息,由於scrollrunloopUITrackingRunLoopModes模式,不接收輸入源,此時要修改connectionmode

1

[scheduleInRunLoop:[NSRunLoop currentRunLoop]forMode:NSRunLoopCommonModes];

關於-(BOOL)runMode:(NSString )mode beforeDate:(NSDate )date;方法

指定runloop模式來處理輸入源,首個輸入源或date結束退出。

暫停當前處理的流程,轉而處理其他輸入源,當date設置爲[NSDate distantFuture]-(將來,基本不會到達的時間),所以除非處理其他輸入源結束,否則永不退出處理暫停的當前處理的流程。

21  GCD 定時器 與 NSTimer

NSTimer 的定時器是在 RunLoop 中實現的,由於RunLoop在處理各種任務,所以會造成計時器不夠準確,有時候會相對慢一些,有沒有什麼方法會讓計時變得準確?有,使用 GCD 的計時器方法會讓計時器變得相對準確,而且GCD不受RunLoop Mode 影響。

22 UIView 的繪製

      http://www.cnblogs.com/feng9exe/p/8848684.html

      https://www.cnblogs.com/feng9exe/p/8848663.html

     http://m.blog.csdn.NET/majiakun1/article/details/73421480

  1. UIView是可以響應事件的,但是CALayer不能響應事件
  2. UIView主要負責管理內容,而CALayer主要負責渲染和呈現。如果沒有CALayer,我們是看不到內容的。
  3. CALayer維護着三個layer tree,分別是presentLayer TreemodeLayer TreeRender Tree,在做動畫的時候,我們修改動畫的屬性,其實是修改presentLayer的屬性值,而最終展示在界面上的其實是提供UIViewmodelLayer
  • 每個 UIView 內部都有一個 CALayer 在背後提供內容的繪製和顯示,並且 UIView 的尺寸樣式都由內部的 Layer 所提供。兩者都有樹狀層級結構,layer 內部有 SubLayers,View 內部有 SubViews.但是 Layer 比 View 多了個AnchorPoint
  • 在 View顯示的時候,UIView 做爲 Layer 的CALayerDelegate,View 的顯示內容取決於內部的 CALayer 的 display
  • CALayer 是默認修改屬性支持隱式動畫的,在給 UIView 的 Layer 做動畫的時候,View 作爲 Layer 的代理,Layer 通過 actionForLayer:forKey:向 View請求相應的action(動畫行爲)
  • layer 內部維護着三分layer tree,分別是 presentLayer Tree(動畫樹),modeLayer Tree(模型樹), Render Tree(渲染樹),在做 iOS動畫的時候,我們修改動畫的屬性,在動畫的其實是 Layer 的 presentLayer的屬性值,而最終展示在界面上的其實是提供 View的modelLayer
  • 兩者最明顯的區別是 View可以接受並處理事件,而 Layer 不可以



作者:不簡單的風度
鏈接:https://www.jianshu.com/p/ed40da9303b1
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯繫作者獲得授權並註明出處。

23 AutoLayout相關的幾個易混淆的方法

  A、幾個易混淆的方法 :http://blog.csdn.net/bravegogo/article/details/79241188   

  B、UIView在AutoLayout下的佈局過程 :https://blog.csdn.net/haungcancan/article/details/52996789

24 NSString 什麼時候用strong ,什麼時候用copy

http://www.cocoachina.com/ios/20150512/11805.html

25 OC內存分配,對象在內存中的存儲

http://blog.csdn.net/bravegogo/article/details/79391728

 

26 C++ 指針

http://blog.csdn.net/bravegogo/article/details/79511073

 

28 iOS消息轉發

 

objc在向一個對象發送消息時,發生了什麼? 

objc在向一個對象發送消息時,runtime庫會根據對象的isa指針找到對象實際所屬的類,然後在該類中的方法列表及父類方法列表中尋找方法並運行。如果在最頂層的父類中依然沒找到方法,objc會調用resolveInstanceMethod:方法,讓我們動態爲該對象添加一個函數實現;如果在該方法中仍沒有找到對應的方法,objc會調用forwardingTargetForSelector方法,將該消息轉發給其他對象;如果在調用該方法後仍沒找到對應方法,首先會調用methodSignatureForSelector方法,獲得需要實現函數的參數和返回值類型,如果該消息返回nil則調用doesNotRecognizeSelector方法,程序崩潰,如果返回了函數簽名,runtime會創建NSInvocation對象,並調用forwardInvocation方法給目標對象。

參考:https://www.jianshu.com/p/f9bd98ad5b05

 

 

29 各種鎖

http://www.cocoachina.com/ios/20161129/18216.html

30 主線程判斷

https://www.jianshu.com/p/7f68a3d5b07d

31 POST 提交數據方式(Content-Type)

https://blog.csdn.net/bravegogo/article/details/81866147

 

32  UITableView 的 estimatedRowHeight 和contentSize 計算

https://blog.csdn.net/bravegogo/article/details/84108038

32  Quartz2D\ CoreGraphics\QuartzCore\CoreAnimation\CoreImage\GPUImage

1. Quartz2D是CoreGraphics的一部分API的抽象,不是實際存在的.framework
2. CoreGraphics定義了顏色、位置、字體、路徑、圖片等UIKit的常見屬性。是構成UIKit的基石。
3. QuartzCore和CoreAnimation是雌雄同體的同義詞。
4. CoreAnimation定義了動畫類來對layer做動畫,定義了layer來呈現內容。定義了仿射變換來做3D動畫。
5. CoreImage定義了濾鏡,來對圖片進行顏色過濾混合等操作。

6.GPUImage是一個著名的圖像處理開源庫,它讓你能夠在圖片、視頻、相機上使用GPU加速的濾鏡和其它特效。與CoreImage框架相比,可以根據GPUImage提供的接口,使用自定義的濾鏡。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章