what new swift 3.0
Tất cả tham số hàm đều có nhãn (tên) Ở Swift 2.0, ta đã chứng kiến sự thay đổi trong cách gọi hàm (function) và phương thức (method). Và với phiên bản 3.0 này, ta sẽ lại lần nữa thấy sự thay đổi này, ở một mức độ cao hơn nữa. Từ Swift 2.x trở về trước, tên phương thức không yêu cầu nhãn ở tham ...
Tất cả tham số hàm đều có nhãn (tên)
Ở Swift 2.0, ta đã chứng kiến sự thay đổi trong cách gọi hàm (function) và phương thức (method). Và với phiên bản 3.0 này, ta sẽ lại lần nữa thấy sự thay đổi này, ở một mức độ cao hơn nữa. Từ Swift 2.x trở về trước, tên phương thức không yêu cầu nhãn ở tham số đầu tiên, nên tên của tham số đầu thường dính luôn vào tên phương thức. Ví dụ:
"TamPN".writeToFile("filename", atomically: true, encoding: NSUTF8StringEncoding) SKAction.rotateByAngle(CGFloat(M_PI_2), duration: 10) UIFont.preferredFontForTextStyle(UIFontTextStyleSubheadline) override func numberOfSectionsInTableView(tableView: UITableView) -> Int func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? NSTimer.scheduledTimerWithTimeInterval(0.35, target: self, selector: #selector(createEnemy), userInfo: nil, repeats: true)
Swift 3 sẽ mặc định yêu cầu nhãn cho tham số (có thể điều chỉnh để thay đổi), đồng nghĩa với việc tên phương thức sẽ không còn nêu chi tiết các tham số nữa. Trong thực tế, phần cuối của tên hàm thường sẽ chuyển thành tên của tham số đầu.
dưới đây là một vd trong Swift 2.2 kèm theo ví dụ tương ứng trong Swift 3:
names.indexOf("TamPN ") names.index(of: "TamPN ") "TamPN ".writeToFile("filename", atomically: true, encoding: NSUTF8StringEncoding) "Taylor".write(toFile: "somefile", atomically: true, encoding: NSUTF8StringEncoding) SKAction.rotateByAngle(CGFloat(M_PI_2), duration: 10) SKAction.rotate(byAngle: CGFloat(M_PI_2), duration: 10) UIFont.preferredFontForTextStyle(UIFontTextStyleSubheadline) UIFont.preferredFont(forTextStyle: UIFontTextStyleSubheadline) override func numberOfSectionsInTableView(tableView: UITableView) -> Int override func numberOfSections(in tableView: UITableView) -> Int func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? func viewForZooming(in scrollView: UIScrollView) -> UIView? NSTimer.scheduledTimerWithTimeInterval(0.35, target: self, selector: #selector(createEnemy), userInfo: nil, repeats: true) NSTimer.scheduledTimer(timeInterval: 0.35, target: self, selector: #selector(createEnemy), userInfo: nil, repeats: true)
Đấy là các phương thức "gọi", đồng thời cũng gây hiệu ứng domino cho các phương thức "đã gọi": Khi bạn kết nói đến một số framework như UIKit, các phương thức sẽ tuân theo quy luật “không có tên tham số đầu” giống các phiên bản trước (điều này áp dụng cả với Swift 3).
Dưới đây là một số ví dụ điển hình ở Swift 2.2:
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int override func didMoveToView(view: SKView) override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) func textFieldShouldReturn(textField: UITextField) -> Bool
Với Swift 3, tất cả đều cần underscore (_) trước tham số đầu tiên, để báo hiệu rằng caller (Objective-C code) sẽ không dùng nhãn tham số:
override func viewWillAppear(_ animated: Bool) override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int override func didMoveToView(_ view: SKView) override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) func textFieldShouldReturn(_ textField: UITextField) -> Bool
Loại bỏ từ không cần thiết
Khi Swift chuyển thành mã nguồn mở hồi tháng 12 năm "2015, API guildlines của Swift đã tiên đoán trước cả thay đổi của phiên bản 3 với ba từ: “omit needless words” (loại bỏ từ không cần thiết). Và giờ đây ta đã thấy sự thay đổi này trong Swift 3, tên phương thức sẽ loại bỏ các từ hiển nhiên.
VD đơn giản trong Swift 2.2:
let minute = numbers.minElement() attributedString.appendAttributedString(anotherString) names.insert("Jane", atIndex: 0) UIDevice.currentDevice()
Khilàm việc với UIColor, blue, nên blueColor() không cần thiết nữa. Khi nối attributed string với nhau, cần phải xác định rằng đang append một attributed string chứ không phải là elephant?
VD tương ứng trong Swift 3:
let blueColor = UIColor.blue() let minute = numbers.min() attributedString.append(anotherString) names.insert("Tam", at: 0) UIDevice.current()
Như vậy tên phương thức được rút ngắn đi nhiều!
Thay đổi này đặc biệt ảnh hưởng đến string (có nhiều cấu trúc lặp). Để làm rõ hơn, sau đây ta sẽ so sánh trực tiếp, dòng trên của Swift 2.2 và dòng dưới của Swift 3.0:
"Hi".stringByTrimmingCharactersInSet(.whitespaceAndNewlineCharacterSet()) " Hi ".trimmingCharacters(in: .whitespacesAndNewlines()) "Taylor".containsString("ayl") "Taylor".contains("ayl") "1,2,3,4,5".componentsSeparatedByString(",") "1,2,3,4,5".componentsSeparated(by: ",") myPath.stringByAppendingPathComponent("fileName.txt") myPath.appendingPathComponent("fileName.txt") "Hi, world".stringByReplacingOccurrencesOfString("Hi", withString: "Bye") "Hi, world".replacingOccurrences(of: "Hi", with: "Bye") "Hi, world".substringFromIndex(7) "Hi, world".substring(from: 7)
Lưu ý: capitalized vẫn là thuộc tính, nhưng lowercaseString và uppercaseString đã chuyển thành phương thức lowercased() và uppercased().
các ví dụ trên vì bước nhảy đến Swift 3 không quá dài, nhưng vẫn có nhiều thay đổi khác biệt.
Ví dụ như:
dismiss(animated: true, completion: nil)
giờ ta có
dismissViewControllerAnimated(true, completion: nil)
prepareForSegue() cũng có thay đổi tương tự, giờ đây ta có:
override func prepare(for segue: UIStoryboardSegue, sender: AnyObject?)
lowerCamelCase thay cho UpperCamelCase với enum và property
Dù không liên quan (về mặt cú pháp) cho lắm, nhưng cách dùng chữ in hoa trong tên class, struct, property, enum,… của ta vẫn thường theo một quy ước: class, struct và enum dùng UpperCamelCase (MyStruct, WeatherType.Cloudy), property và tên tham số dùng lowerCamelCase (emailAddress, requestString).
Tuy vậy, vẫn có một số ngoại lệ, và các ngoại lệ này sẽ không còn trong Swift 3 nữa: các property và tham số bắt đầu bằng chữ viết tắt giờ đây sẽ dùng lowerCamelCase.
Thay đổi này đôi khi cũng không quá lạ lẫm: Swift 2.2 sử dụng NSURLRequest(URL: someURL) để tạo object NSURLRequest – chú ý đoạn “URL” viết hoa. Swift 3 sẽ viết lại thành NSURLRequest(url: someURL), và cũng đồng nghĩa bạn sẽ phải dùng các lệnh như webView.request?.url?.absoluteString để đọc URL của một web view.
Vậy có thấy khó chịu khi tên property biến thành nửa hoa nửa thường, chỗ thì hoa, chỗ thì thường, như: CGColor hay CIColor? và trong Swift 3, chúng đã biến thành cgColor và ciColor:
let red = UIColor.red().cgColor
Thay đổi này sẽ tăng tính nhất quán hơn: tất cả property và thông số sẽ bắt đầu bằng chữ thường, và sẽ không có ngoại lệ.
Đồng thời, enum case cũng có sự thay đổi, từ UpperCamelCase thành lowerCamelCase.Ttất cả Apple enum bạn sử dụng giờ đây sẽ là chữ thường:
VD:
UIInterfaceOrientationMask.Portrait // cũ UIInterfaceOrientationMask.portrait // mới 3.0 NSTextAlignment.Left // cũ NSTextAlignment.left // mới 3.0 SKBlendMode.Replace // cũ SKBlendMode.replace // mới 3.0
Thay đổi nhỏ trên dẫn đến một sự thay đổi lớn hơn nữa vì optionals của Swift thực tế chính là enum, như:
enum Optional { case One case Two(Wrapped) }
Có nghĩa nếu dùng .Two khi làm việc với optionals, cần phải chuyển thành .two. Tất nhiên có thể tận dụng điều này để hoàn toàn loại bỏ .two – hai đoạn code dưới đây có chức năng như nhau:
for case let .two(somedata) in data { print(somedata) } for case let valuetum? in data { print(somedata) }
Import các hàm chức năng của C
Swift 3 còn giới thiệu attribute cho hàm trong ngôn ngữ C, cho phép người tạo thư viện chỉ định nhiều cách thức mới để nhập code vào Swift thật nhanh chóng và chuẩn xác. Ví dụ như, tất cả các hàm bắt đầu bằng “CGContext” sẽ được map đến các property và method trên một CGContext object. Nói cách khác, cái “mụn cóc xấu xí” CGContextSetFillColorWithColor() cuối cùng cũng đã bị cắt bỏ.
Để thấy rõ hơn, sau đây là ví dụ trong Swift 2.2:
let ucc = UIGraphicsGetCurrentContext() let rectangle = CGRect(x: 0, y: 0, awidth: 512, height: 512) CGContextSetFillColorWithColor(ucc, UIColor.redColor().CGColor) CGContextSetStrokeColorWithColor(ucc, UIColor.blackColor().CGColor) CGContextSetLineWidth(ucc, 10) CGContextAddRect(ucc, rectangle) CGContextDrawPath(ucc, .FillStroke) UIGraphicsEndImageContext()
Trong Swift 3 CGContext có thể xem là object mà bạn có thể call method được, không cần phải lặp lại CGContext liên tục. Vậy, ta có thể viết lại đoạn code trên như sau:
if let ucc = UIGraphicsGetCurrentContext() { let rectangle = CGRect(x: 0, y: 0, awidth: 512, height: 512) ucc.setFillColor(UIColor.red().cgColor) ucc.setStrokeColor(UIColor.black().cgColor) ucc.setLineWidth(10) ucc.addRect(rectangle) ucc.drawPath(using: .fillStroke) UIGraphicsEndImageContext() }
Lưu ý: trong Swift 2.2 lẫn 3.0, UIGraphicsGetCurrentContext() sẽ trả về CGContext tùy chọn, nhưng vì Swift 3.0 dùng phương thức calls, ta phải unwrap cẩn thận trước khi sử dụng.
cũng có thể thấy kiểu mapping hàm C này ở nhiều trường hợp khác, ví dụ: giờ đây có thể đọc property numberOfPages của một CGPDFDocument. Và CGAffineTransform cũng đã cải thiện đáng kể. Sau đây là một số ví dụ cũ và mới:
CGAffineTransformIdentity CGAffineTransform.identity CGAffineTransformMakeScale(1, 1) CGAffineTransform(scaleX: 1, y: 1) CGAffineTransformMakeTranslation(221, 221) CGAffineTransform(translationX: 221, y: 221) CGAffineTransformMakeRotation(CGFloat(M_PI)) CGAffineTransform(rotationAngle: CGFloat(M_PI))
Danh từ và Động từ
Khi operation được miêu tả bằng động từ, sử dụng thể mệnh lệnh của động từ với mutating method và thêm hậu tố “ed” hoặc “ing” để đặt tên cho các method không mutate tương ứng Nên sử dụng thể quá khứ phân từ của động từ để đặt tên của biến không mutate Khi Thêm “ed” không đúng ngữ pháp vì động từ có tân ngữ trực tiếp, dùng hiện tại phân từ của động từ để đặt tên biến không mutate “Khi operation được miêu tả bằng danh từ, dùng danh từ với method không mutate và thêm tiền tố “form” để đặt tên mothod có mutate tương ứng. Tuy vậy, việc này có thể gây nhiều khó khăn cho các bạn yếu anh ngữ, bởi nhiều tên method sẽ có nhiều sự thay đổi.
ví dụ:
arr.enumerate() arr.enumerated() arr.reverse() arr.reversed()
Swift 3 điều chỉnh method với “d” thêm vào cuối: đây là giá trị được trả về.
Quy luật này đặc biệt làm dễ nhầm lẫn khi sắp xếp array. Swift 2.2 dùng sort() và trả array đã sắp xếp, và sortInPlace() để sắp xếp array tại chỗ. Trong Swift 3.0, sort() đổi thành sorted() như ví dụ trên, và sortInPlace() đổi thành sort().
phải cẩn thận chỗ này vì sort() trong Swift 2.2 trả kết quả array được sắp xếp, còn sort() trong swift 3.0 lại sắp xếp array tại chỗ.
Tại sao phải thay đổi?
những thay đổi này của Apple nhằm giúp ngôn ngữ dễ học hơn, dễ dùng hơn, và nhanh hơn nữa (đặc biệt với người mới học). Giúp cho các dòng code tường minh và ngắn gọn hơn, và đặc biệt giúp cho lập trình viên dễ tiếp cận và giảm thiểu những chi tiết thừa ko cần thiết.