轉載作者 香蕉大大 (Github)
開發過程中我特別喜歡用語法糖,原因很簡單,懶得看到一堆長長的代碼,但是語法糖我今天無意中看到更有意思的玩法.這裡暫時吧把今天新學到的知識點整理一下希望大家喜歡,如果有更好的補充希望能和我說下,我希望更更加好的完善。
語法糖
(Syntactic sugar
),也譯為糖衣語法
,是由英國計算機科學家彼得·約翰·蘭達(Peter J. Landin)發明的一個術語,指計算機語言中添加的某種語法,這種語法對語言的功能並沒有影響,但是更方便程序員使用。通常來說使用語法糖能夠增加程序的可讀性,從而減少程序代碼出錯的機會。
本文的目錄如下
OC語法糖
基礎
@[],@{}用法在NSArray,NSDictionary,NSNumber使用
!重點!
@()使用
!重點!
語法糖在UI中的使用方法
swift
基礎
if let 與 guard 語法糖
基礎
語法糖Selector例子
常用基礎使用部分@[],@{}這兩部分的用法
1.一般數組的初始化和訪問數組元素是這樣的在之前的博客中我是這樣初始化NSArray的:
//NSArray的便利初始化 NSArray *array1 = [[NSArray alloc] initWithObjects:@"aaa", @"bbb", @"ccc", nil]; //NSArray的便利構造器 NSArray *array2 = [NSArray arrayWithObjects:@"111", @"222", @"333", nil];
獲取數組的元素
//獲取相應索引的元素 id element = [array1 objectAtIndex:0]; NSLog(@"array1_count = %d, array[0] = %@", count, element);
簡化後的數組初始化和訪問的做法如下
//NSArray的定義 NSArray *array = @[@"lu", @"da", @"shi", @YES, @123]; int count = (int)[array count]; for (int i = 0; i < count; i++) { NSLog(@"%@", array[i]); }
2.對字典(NSDictionary)的簡化也引用我之前博客中得一段代碼吧
//不可變字典的初始化 NSDictionary *dictionay = [NSDictionary dictionaryWithObjectsAndKeys:@"value1", @"key1", @"value2", @"key2", nil]; id value = [dictionay objectForKey:@"key1"]; NSLog(@"key1 => %@", value);
我們還可以這樣做
//NSDictionary的定義簡化 NSDictionary *dictionary = @{ @"key0" : @"value0", @"key1" : @"value1", @"key2" : @"value2" }; NSLog(@"key2 => %@", dictionary[@"key2"]);
3.對NSNumber簡化
我們可以這樣做
把基本類型包裝成對象的便利構造函數 -(id) initWithChar : (char) value; -(id) initWithInt : (int) value; -(id) initWithFloat : (float) value; -(id) initWithBool: (BOOL) value; 把基本數據類型包裝成對象的便利構造器 +(id) numberWithChar : (char) value; +(id) numberWithInt : (int) value; +(id) numberWithFloat : (float) value; +(id) numberWithBool : (BOOL) value;
我們也可以這樣做,說明:在char轉換為NSNumber是存的是ASCII碼的形式,c輸出為97
//NSNumber的簡化 NSNumber *a = @123; NSNumber *b = @11.2; NSNumber *c = @('a'); NSLog(@"a = %@, b = %@, c = %@", a, b, c);
針對以上部分的簡單練習
//NSNumber的語法糖 NSNumber *intNumber = [NSNumber numberWithInt:100]; NSNumber *intNumber2 = @100; //不可變字符串的語法糖 NSString *string = @"hanjunqiang"; //可變字符串的語法糖 NSMutableString *mString = @"大愛中華".mutableCopy;//後綴不能丟 //不可變數組的語法糖 NSArray *array = @[@"1",@"2",@"3",@"4"]; NSLog(@"%@",array); //訪問數組元素的語法糖 NSLog(@"%@",array[1]); //可變數組的語法糖 NSMutableArray *mArray = @[@"1",@"2",@"3",@"4"].mutableCopy; //字典的語法糖 //字典對象[key值]取出對應的value值 NSDictionary *dict = @{@"a":@"1",@"b":@"2"};//key值在冒號前,value值在冒號後 NSLog(@"%@",dict); NSLog(@"%@",dict[@"a"]); //可變字典可以賦值和修改值 NSMutableDictionary *mDic = @{@"a":@"1",@"b":@"2"}.mutableCopy; mDic[@"a"]=@"100"; NSLog(@"%@",mDic[@"a"]);
@()介紹以及使用
在 Objective-C 中我們可以用 @”foo” 來創建一個 NSString 常量,看起來似乎平淡無奇。
但它背後其實比想象的精彩,@ 可以被理解成一個特殊的宏,其接受一個 C 字符串作為參數,也可寫作 @(“foo”)。
之所以說 @ 是一個特殊的宏,是因為其能根據傳入的 C 字符串類型不同——C 字符串常量或 C 字符串——在運行時構建返回不同類型的 NSString,
參見下面的代碼:
char* obtain_c_string(void) { return "c_string"; } NSLog(@"%@", @"foo".class); NSLog(@"%@", @("bar").class); NSLog(@"%@", @(obtain_c_string()).class); NSLog(@"%@",@"aaa"); NSLog(@"%@",@("aaa"));
輸出如下__NSCFConstantString
__NSCFConstantString
__NSCFString
aaa
aaa
可見,如果傳入的是 C 字符串常量,運行時
構建的則為 NSConstantString
;如果傳入的是C 字符串
則創建的是 NSString
。
眾所周知,Objective-C 代碼裡有很多地方需要我們把代碼中的一些文法串寫成字符串再作為傳入參數,比如 KVO 中的 keyPath 參數往往就要傳入形如 propertyA.propertyB 的字符串,從實用角度出發這有兩個弊端: 寫字符串的時候沒有代碼提示,很容易寫錯 即便一開始寫對了,如果後來相關類重構了,keyPath 的參數便失效了,而 Xcode Refactor 無法掃描字符串 當我們理解了 @(),再加上自定義的宏,上述兩個問題便可迎刃而解。
/** * # 將宏的參數字符串化,C 函數 strchr 返回字符串中第一個 '.' 字符的位置 */ #define Keypath(keypath) (strchr(#keypath, '.') + 1) // 有代碼提示,可以被重構掃描到 [objA addObserver: objB forKeyPath: @Keypath(ObjA.property1.property2) options: nil context: nil];
UI使用部分
拿UIImageView來做例子,原來創建對象和下面一致
self.imageView = [[UIImageView alloc] init]; self.imageView.backgroundColor = [UIColor redColor]; self.imageView.image = [UIImage imageNamed:@"12345"]; self.imageView.frame = CGRectMake(0, 0, 100, 100); [self.view addSubview:self.imageView];
重點來了
這個就是語法糖在UI中創建對象的使用,瞬間感覺很高大上~
self.imageView = ({ UIImageView *imageView = [[UIImageView alloc] init]; imageView.backgroundColor = [UIColor redColor]; imageView.image = [UIImage imageNamed:@"12345"]; imageView.frame = CGRectMake(0, 0, 100, 100); [self.view addSubview:imageView]; imageView; });
if let 與 guard 語法糖
話說if let 和 guard 只是語法糖,沒有也可以,但有了可以使得代碼更簡潔方便。要理解 if let 和 guard,不妨設想假如沒有這兩者,代碼會怎麼寫。
if let func doSomething(str: String?) { let v: String! = str if v != nil { // use v to do something } }
Swift 中因為有optional, 經常需要判斷是否為空。假如沒有if let,大致寫成上面的樣子,有了if let, 可以改寫成
func doSomething(str: String?) { if let v = str { // use v to do something } }
上面兩段代碼的控制流是一樣的。對照著,可以看出if let的寫法更加簡潔方便。
guard 假如if中出現的代碼很長,我們寫代碼時可以將錯誤情況先返回。比如: func doSomething(str: String?) { let v: String! = str if v == nil { return } // use v to do something }
這樣做可以避免過多的嵌套。上面代碼實在太常見了,swift也提供一個guard這個語法糖,用guard可以改寫成:
func doSomething(str: String?){ guard let v = str else { return } // use v to do something }
上面兩段代碼的控制流是一樣的。也可以看出guard的寫法更加簡潔方便。
至於if let 和 guard 語法中出現的where,只是附加一些條件。相當於邏輯運算 && 和 ||。SQL中的條件語法也是用where這個關鍵字。
假如還不理解,動手將一段代碼,不用if let 和 guard 進行改寫。試多幾次,就會發覺很自然了。
語法糖Selector例子
創建控制器,添加Button
override func viewDidLoad() { super.viewDidLoad() let btn = UIButton(frame: CGRectMake(100,100,100,100)) btn.backgroundColor = UIColor.redColor() view.addSubview(btn) } func printFire() { print("fire") }
想實現控制器裡的Button點擊事件,但是,如果一個控制器裡的Button特別的多,那添加Button點擊事件的Selector 會覺得特別的臃腫。所以語法糖就是要拓展Selector
private extension Selector { static let printFire = #selector(ViewController.printFire) }
我們現在給viewDidLoad方法中的Button 添加點擊事件
btn.addTarget(self, action: .printFire, forControlEvents: .TouchUpInside)
如果Button過多的話,用語法糖方便管理Button的點擊事件,又不會把點擊事件變得過於臃腫
下面是控制器的完整代碼
import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let btn = UIButton(frame: CGRectMake(100,100,100,100)) btn.backgroundColor = UIColor.redColor() btn.addTarget(self, action: .printFire, forControlEvents: .TouchUpInside) view.addSubview(btn) } func printFire() { print("fire") } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } } private extension Selector { static let printFire = #selector(ViewController.printFire) }