說說iOS中的常用的關鍵字static ,class(僅限Swift關鍵字)
本文說說static在iOS中的作用包括OC和Swift,並講解常用的情況.程式碼主要以OC為主,Swift中主要描述和另外一個關鍵字class的異同
當static修飾區域性變數時
- 變數在記憶體中的位置: 當用static修飾區域性變數時,區域性變數的記憶體地址會從棧變為全域性區(靜態區)
- 作用域:只在函式內部可見,只初始化一次,所以也只有一個記憶體地址
- 生命週期程式結束時才釋放
- (void)viewDidLoad { [super viewDidLoad]; [self tobeYoung]; [self tobeYoung]; [self tobeYoung]; static int age = 20;//使用static修飾的區域性變數,在其他的函式中宣告相同變數名的變數時,是一個全新的變數 NSLog(@"age===%d",age); // Do any additional setup after loading the view, typically from a nib. } - (void)tobeYoung { static int age = 10; age--; NSLog(@"age===%d",age); } // 控制檯的輸出結果 2018-11-29 22:46:31.602384+0800 static[1260:222387] age===9 2018-11-29 22:46:31.602557+0800 static[1260:222387] age===8 2018-11-29 22:46:31.602672+0800 static[1260:222387] age===7 2018-11-29 22:46:31.602758+0800 static[1260:222387] age===20 //每次的輸出結果都不一樣,被static修飾的區域性變數記憶體地址只有一份,只被初始化一次,所有第二次呼叫tobeYoung方法時age沒有被重新初始化,所以是9,9--之後就是輸出8了 複製程式碼
- 常用情況講解:我們經常在tableViewcell複用的時候使用到static,為什麼需要在區域性變數identifier之前加上static.我們先看看常用的寫法
- (nonnull UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { static NSString * identifier = @"cellIdentifier"; UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:identifier]; if (!cell) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier]; } return cell; } 複製程式碼
tableview的這個代理方法是一個會被反覆呼叫的方法,當identifier的前面不加static修飾時,identifier這個臨時變數是儲存在棧中的,指向常量區中的@"cellIdentifier",一旦這個代理方法執行完畢,identifier這個區域性變數就會被回收.當再次呼叫的時候又會重新生成一個區域性變數重新指向常量區的@"cellIdentifier".,消耗記憶體.
當使用static修飾identifier時,identifier的記憶體就會被分配在全域性區(靜態區),生命週期會變成這個程式的執行時間,不會隨著代理方法呼叫完畢而銷燬,一直指向常量區的@"cellIdentifier".當再次呼叫時不需要重新生成.節省記憶體
當static修飾全域性變數時
- 記憶體中的位置 :仍然是在靜態儲存區沒變,生命週期為整個程式執行期間.
- 作用域 :在整個宣告它的檔案中可用,在宣告他之外的檔案之外不可見
- 常用情況:iOS中的單例中的全域性變數會用static修飾
#import "Singleton.h" @implementation Singleton static Singleton * instance = nil; + (Singleton *)getInstance{ if (instance == nil) { instance = [[Singleton alloc] init]; } return instance; } + (id) allocWithZone:(struct _NSZone *)zone{ if (instance == nil) { instance = [super allocWithZone:zone]; } return instance; } - (id) copyWithZone :(struct _NSZone*)zone{ return instance; } @end 複製程式碼
為什麼一定要用static 來修飾變為一個靜態變數,而不是寫成一個例項變數.因為單例是程式生命週期中唯一的例項,為確保例項化的唯一.而利用類的類方法來生成,而在類方法中不可以使用例項物件的變數,只能使用屬於類的(static)類變數(一般在OC中沒有特意區分static變數和類變數的區別).而且在宣告它之外的檔案不可見.
/** 在其他的類中實用extern來訪問 */ extern Singleton * instance ; NSLog(@"instance====%@",instance); 直接無法編譯過會直接報錯 Undefined symbols for architecture x86_64: "_instance", referenced from: -[ViewController viewDidLoad] in ViewController.o ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation) 複製程式碼
在Swift中static的使用(包含與關鍵字class的異同)
說道Swift中的static那就不得不說到另一個關鍵字class,在Swift中static和class都是用來描述型別作用域這一概念.兩者都可以用來修飾計算型別.都可以用來修飾方法,static修飾的方法叫做靜態方法,class修飾的是類方法.(在OC中我們不會特別的區分類方法,類變數,靜態方法,靜態變數),但是在Swift中class和static,無論是能夠修飾的範圍還是修飾後產生的效果區別都很大,不能混為一談.
- class 和 static相同點
- 都可以在class中修飾方法,static修飾的叫做靜態方法,class修飾的叫做類方法.
- 都可以修飾class中的計算屬性
class Programmer :NSObject { static var name : String{ return "老王" } class var nickname :String { return "王重陽" } class func writeTheCode() -> Void { print("寫程式碼") } static func fixTheBug() -> Void { print("修復bug") } } 複製程式碼
- class 和static中的不同點
- 首先class修飾的屬性和方法可以被子類重寫,但是static不能被重寫
class iOSProgrammer :Programmer{ // 重寫計算屬性 可以使用static 來重寫,但是static 重寫後,就不能被它的子類再次重寫了 static override var nickname: String{ return "iOS王重陽" } // 重寫類方法時可以使用static 讓其變成靜態方法 static override func writeTheCode() -> Void { print("寫程式碼") } } 複製程式碼
- 其次class 和static能夠修飾的範圍不一樣,class只能在class中修飾,而static可以不僅可以作用於class中,也可以在enum,和struct中使用.