本文說說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修飾的類方法被重寫時,可以使用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中使用.
通篇有限今天暫時到此為此,如有錯誤,希望大家幫忙在評論中指出,歡迎大家來交流溝通.