Swift vs Objective C (part 2)
Sức mạnh của enum Enum của Objective-C chính là enum trong ngôn ngữ C. Trong khi đó, enum của Swift thì phong phú hơn nhiều. Hãy check ví dụ dưới đây: enum Company { case Apple , Google , MicroSoft func getBrowser ( ) - > String { switch ...
Sức mạnh của enum
Enum của Objective-C chính là enum trong ngôn ngữ C.
Trong khi đó, enum của Swift thì phong phú hơn nhiều.
Hãy check ví dụ dưới đây:
enum Company { case Apple, Google, MicroSoft func getBrowser() -> String { switch self { case .Apple: return "Safari" case .Google: return "Chrome" case .MicroSoft: return "IE" } } } let apple = Company.Apple let mobileOS = apple.getBrowser();
Không cần thêm prefix vào các giá trị của enum
Ở đoạn code trên, chúng ta có thể sử dụng được Company.Apple.
Nếu là Objective-C thì phải thêm prefix vào và khai báo rườm rà như dưới đây
(trong ObjC nếu không gán prefix thì Apple sẽ trở thành biến global)
file.m typedef NS_ENUM(NSUInteger, Company) { // Phải đính kèm prefix kiểu CompanyXXX cho từng cái CompanyApple, CompanyGoogle, CompanyMicroSoft };
Có thể xử lý dựa vào giá trị của enum
Ví dụ như apple.getBrowser() ở trên, bản thân enum có thể xử lý dữ liệu, cá nhân tôi thấy có thể ứng dụng được rất nhiều.
Khi sử dụng enum, rất nhiều trường hợp ứng với giá trị khác nhau thì xử lý logic khác nhau, nếu chỉ với 1 enum mà phải phân nhánh switch ở nhiều nơi thì thực sự không tốt, khi thêm giá trị mới vào enum có khi lại phát sinh bug nữa.
Để giải quyết vấn đề này, Objective-C phải tạo class chả hạn để wrap lại enum đó, nhưng thực sự là việc tạo class chỉ với mục đích như thế thật là tốn công.
Do đó câu trả lời đơn giản nhất cho vấn đề trên là cho phép xử lý dữ liệu ngay trong bản thân enum.
Có thể gán associated values vào enum
Trong Swift, có thể gán giá trị tham số cho enum ứng với từng context.
Khi sử dụng chức năng này, cần chỉ định sẵn kiểu giá trị muốn nhận lại.
Ví dụ có thể định nghĩa enum như dưới đây để gán từng giá trị Result, Error của ServerResponse:
enum ServerResponse { case Result(String, String) case Error(String) }
Ví dụ sử dụng đoạn code trên trong thực tế:
let success = ServerResponse.Result("6:00 am", "8:09 pm") let failure = ServerResponse.Error("Out of cheese.") switch success { case let .Result(sunrise, sunset): let serverResponse = "Sunrise is at (sunrise) and sunset is at (sunset)." case let .Error(error): let serverResponse = "Failure... (error)" }
Trong trường hợp này ở Objective-C , nếu không sử dụng Class thì không thể thực hiện được, nên ở Swift chỉ cần dùng enum đã làm được thì đúng là 1 điểm cộng cho Swift.
Có thể lấy giá trị default trong tham số của hàm số
Đầu tiên hãy xem việc khai báo hàm số thông thường.
Hàm số postBlog có 2 tham số: title (kiểu String) và body (kiểu String).
func postBlog(title: String, body: String) -> Bool { ... return true; } let bool = postBlog("眠い","本文です")
Trong ví dụ bên trên, nếu chỉ định giá trị default của body là "空っぽ" thì code sẽ như sau:
func postBlog(title: String , body: String = "空っぽ") -> Bool { ... return true; } let bool = postBlog("眠い") // tương đương với postBlog("眠い","空っぽ"')
Đoạn code trên nhìn có vẻ rất bình thường, tuy nhiên trong Objective-C, để thực hiện thao tác được với tham số default thì vất vả hơn nhiều. Ví dụ như nếu viết code tương tự bằng ObjC thì code sẽ như sau.
file -(void)postWithTitle:(NSString *)title body:(NSString)body{ ... } -(void)postWithTitle:(NSString *)title{ [self postWithTitle:title body:@"空っぽ"]; }
Sử dụng cách viết trên, tham số tăng lên thì phiền phức thật.
Thế nên nếu có thể sử dụng tham số default 1 cách tự nhiên đơn giản thì thật tuyệt vời.
Cách viết Closure dễ hiểu hơn
Trong Objective-C cũng có thể xử lý Closure khi sử dụng Blocks, tuy nhiên cách nhận tham số khác với method thông thường, lại không mang tính trực giác nên khó nhớ nổi.
Về điểm này, ở Swift thì cách nhận tham số giống với hàm số bình thường.
Dưới đây là ví dụ về việc thực hiện truyền Closure vào Array#map, tạo array có các giá trị bên trong gấp đôi array khác.
let numbers = [1, 2, 3, 4] let doubledNumbers = numbers .map({ (number: Int) -> Int in let result = 2 * number return result }) // doubledNumbers : [ 2, 4, 6, 8]
Cách viết (number: Int) -> Int là cách viết tương tự như định nghĩa tham số của hàm số thông thường, nên so với ObjC thì không bị tình trạng khó nhớ nữa.
Ngoài ra, ngôn ngữ có Array#map thật là tuyệt.
Dưới đây là cách định nghĩa hàm số bằng Closure.
// Hàm số trả lại giá trị tổng của 2 tham số nhận được func addTowNumbers(numA:Int , numB:Int) -> Int { return numA + numB } let result = addTowNumbers(1,3) // result: 4
Thật là dễ hiểu phải không.
Để so sánh, hãy cùng viết Blocks tương tự cho Objective-C.
int (^addTowNumbers)(int) = ^(int numA,int numB) { return numA + numB; }; int result = addTowNumbers(1,3);
Trong Objective-C có quá nhiều ký hiệu dẫn đến việc code khó khăn hơn nhiều so với Swift ngắn gọn.
Định nghĩa Class trực quan
Nhìn vào đoạn code ngay từ đầu đã có thể hiểu được class này làm gì.
class Human { var name: String init(name: String) { self.name = name } func sayHello() -> String { return "Hello. I'm (self.name)." } } let tarou = Human("Tarou Yamada") ikari.sayHello() // Hello. I'm Tarou Yamada
Với Objective-C thì phải alloc rồi initWithName, không thì phải tạo factory method theo kiểu [Human humanWithName:@"Tarou Yamada"].
Không phải sử dụng alloc thật sướng