- Ai đã từng viết code bằng Php, Python hay Ruby thì sẽ không lạ với Swift.
Trang chủ của Swift. Bạn có thể tìm được những hướng dẫn bằng pdf cho ngôn ngữ Swift. Tài liệu về Swift. Từ bây giờ ngôn ngữ Swift đã được OutSource, các bạn có thể vào trang https://swift.org/ để tham khảo.
Những nội dung chính của trang này:
1. Cú pháp:
let implicitInteger = 70; let implicitDouble = 70.0; let explicitDouble: Double = 70
- @UIApplicationMain Là thuộc tính trong swift dùng để thay thế file main.m để báo cho hệ thống biết file này chạy đầu tiên khi chạy chương trình, xem thêm tại đây.
- Objective C: dùng cú pháp "#pragma mark - " để đánh dấu phân vùng. "#pragma mark *" Dùng để tạo tiêu đề.
- Swift: dùng cú pháp "// MARK: - " để đánh dấu phân vùng. "// MARK: *" Dùng để tạo tiêu đề.
2. Những kiểu file trong swift:
- .swift là file được viết bằng ngôn ngữ swift. Bạn có thể chạy file này thông qua terminal.
3. Chạy file Swift theo lệnh script:
4. Kết hợp ngôn ngữ Swift và Objctive-C:
5. Những khái niệm căn bản:
- var để khai báo biến.
var myVariable = 42 //Value 42
myVariable = 50 //Value 50
let myConstant = 42 //Value is 42
myConstant = 50 // Occur error
- Kiểu giá trị được xác định theo giá trị truyền vào:
let implicitInteger = 70
let implicitDouble = 70.0
- Hoặc bạn có thể khai báo trực tiếp kiểu dữ liệu (Annotation) bằng cách kiểu dữ liệu viết sau biến và phân cách bằng dấu 2 chấm:
let explicitDouble: Double = 70
- Tên hằng và biến có thể đặt bất kỳ ký tự nào cũng được kể cả ký tự Unicode, ví dụ như:
let π = 3.14159
let 你好 = "你好世界"
let 🐶🐮 = "dogcow”
- Numeric Literals:
Integer literal có thể được viết như sau:
let decimalInteger = 17
let binaryInteger = 0b10001 // 17 in binary notation
let octalInteger = 0o21 // 17 in octal notation
let hexadecimalInteger = 0x11 // 17 in hexadecimal notation
Theo ví dụ trên thì bạn thấy số decimal thông thường thì không có tiền tố đầu(prefix), Prefix của dạng binary là 0b, dạng octal là 0o, dạng hexadecimal là 0x.Đối với số decimal, dùng chữ e thay cho toán học số mũ (exponent), một số cơ sở nhân cho 10exp:
let positiveExponent = 1.25e2 //means 1.25 × 102, or 125.0.
let negativeExponent = 1.25e-2 //means 1.25 × 10-2, or 0.0125.
Đối với số hexadecimal, dùng chữ p thay cho toán học mũ (exponent), một số cơ sở nhân cho 2exp:
let positiveHexExponent = 0xFp2 //means 15 × 22, or 60.
let negativeHexExponent = 0xFp-2 //means 15 × 2-2, or 3.75.
Bạn có thể dùng dấu gạch chân(underscores) để cho dễ đọc 1 số lớn như số hàng triệu và hàng tỷ:
let paddedDouble = 000123.456 //means 123.456
let oneMillion = 1_000_000 //means 1000000
let justOverOneMillion = 1_000_000.000_000_1 //means 1000000.0000001
- Numeric Type Convertion:
+ Integer Convertion:
Giả sử bạn có 2 biến kiểu UInt16 và UInt8 và dùng toán tử cộng với nhau, thì bắt buộc bạn phải chuyển biến kiểu dữ liệu nhỏ sang kiểu dữ liệu lớn thì mới có thể cộng được, theo cách này chúng ta sẽ viết code như sau:
Trường hợp mình cộng mà không ép kiểu sẽ bị lỗi như bên dưới:
và trường hợp ép kiểu từ lớn sang nhỏ sẽ bị lỗi như sau:
Bởi vì theo nguyên tắc bạn mở rộng thêm vùng nhớ thì không gặp sự cố gì còn nếu thu hẹp vùng nhớ lại thì có nguy cơ bị mất dữ liệu tại vùng nhớ bị thu hẹp lại.
+ Integer và Floating-point convertion:
Giả sử bạn có toán tử cộng giữa kiểu số nguyên và số thực, thì bạn phải ép kiểu từ số nguyên sang số thực bằng Double (mặc định khai báo kiểu số thực là Double):
Ngược lại nếu bạn không ép kiểu thì sẽ báo lỗi như sau:
- Kiểu Alias: Bạn có thể dùng từ khoá typealias để định danh 1 tên thay thế cho kiểu dữ liệu đã có sẵn rồi, giả sử có đoạn code như sau:
typealias AudioSample = UInt16
var maxAmplitudeFound = AudioSample.min // maxAmplitudeFound is now 0”
- Những kiểu dữ liệu không tự động chuyển sang kiểu dữ liệu khác, bạn phải chuyển chúng sang như ví dụ sau:
let label = "The width is "
let width = 94
let widthLabel = label + String(width)
String Interpolation: Là cách tạo chuỗi mới bằng cách kết hợp những hằng (constants), biến (variables), literal, biểu thức (expression).Bạn có thể dùng backslash và dấu ngoặc tròn '\()' để có thể gán biến giá trị vào kiểu String như sau:
let apples = 3
let oranges = 5
let appleSummary = "I have \(apples) apples."
let fruitSummary = "I have \(apples + oranges) pieces of fruit."
Cách này sẽ được dùng nhiều vì thế các bạn nên chú ý cú pháp này.- Khởi tạo array và dictionary dùng bracket ([]), và truy cập đến những phần tử của chúng:
var shoppingList = ["catfish", "water", "tulips", "blue paint"]
shoppingList[1] = "bottle of water"
var occupations = [
"Malcolm": "Captain",
"Kaylee": "Mechanic",
]
occupations["Jayne"] = "Public Relations"
Khởi tạo array và dictionary rỗng dùng theo cú pháp này ta sẽ viết như sau://Có kiểu dữ liệu
let emptyArray = [String]()
let emptyDictionary = [String: Float]()
//Không có kiểu dữ liệu sẵn
let emptyArray = []
let emptyDictionary = [:]
- Giá trị Optional được khai báo bằng cách thêm dâu chấm hỏi đằng sau kiểu giá trị như sau:
var optionalString: String? = "Hello"
println(optionalString == nil)
- Toán tử nil Coalescing (a ?? b): Khi bạn cần kết quả trả về luôn khác nil vì có giá trị mặc định, thì nên áp dụng toán tử này vào. Điều kiện áp dụng toán tử này: a luôn là kiểu Optional, b phải là hằng hay 1 biến khác nil. Nếu a bằng nil thì giá trị trả về là b, ngược lại a khác nil thì bằng giá trị a.
Cú pháp toán tử này được viết tắt như sau:
a != nil ? a! : b
Code ví dụ:
let defaultColorName = "red"
var userDefinedColorName: String? // defaults to nil
var colorNameToUse = userDefinedColorName ?? defaultColorName
// userDefinedColorName is nil, so colorNameToUse is set to the default of "red"
userDefinedColorName = "green"
colorNameToUse = userDefinedColorName ?? defaultColorName
// userDefinedColorName is not nil, so colorNameToUse is set to "green"
- Range Operators:
+ Closed Range Operator (a...b): Dùng để định nghĩa khoảng cách từ a đến b, bao gồm cả b. Được dùng nhiều trong vòng lặp for.
+ Half-Open Range Operator (a..<b): Dùng để định nghĩa khoảng cách từ a đến b, không bao gồm b. Được dùng nhiều trong vòng lặp for.
- Logical Operators: như những ngôn ngữ lập trình khác gồm toán tử NOT (!a), AND (a && b) và OR (a || B).
- Có thể dùng toán tử addition (+) và addition assignment (+=) để ghép chuỗi string, và hàm append để thêm 1 ký tự (character) vào chuỗi string, code ví dụ như sau:
Toán tử == để so sánh bằng giữa 2 chuỗi.
- Những ký tự đặc biệt trong String Literal:
+ The escaped special characters \0 (null character), \\ (backslash), \t (horizontal tab), \n (line feed), \r (carriage return), \" (double quote) and \' (single quote)
+ An arbitrary Unicode scalar, written as \u{n}, where n is a 1–8 digit hexadecimal number with a value equal to a valid Unicode code point
Code ví dụ như sau:
let wiseWords = "\"Imagination is more important than knowledge\" - Einstein"
// "Imagination is more important than knowledge" - Einstein
let dollarSign = "\u{24}" // $, Unicode scalar U+0024
let blackHeart = "\u{2665}" // ♥, Unicode scalar U+2665
let sparklingHeart = "\u{1F496}" // 💖, Unicode scalar U+1F496
Các bạn có thể xem thêm danh sách những ký tự unicode tại đây.Trong blog này có nói việc string trong swift 2 đã giống như array. 1 string bây giờ giống như 1 mảng chứa danh sách những ký tự.
- Extended Grapheme Clusters: mỗi character trong swift được thể hiện bằng 1 extended grapheme cluster đơn. 1 extended grapheme cluster là một sự nối tiếp của 1 hay nhiều Unicode Scalar để tạo ra 1 ký tự đơn mà con người có thể đọc được. Code ví dụ tạo ký tự như "é", "한",... như sau:
như hình trên bạn thấy thay vì chữ "é" được thể hiện bằng unicode scalar là \u{E9}, thì bạn có thể ghép bằng 2 ký tự unicode scalar khác là "e" (\u{65}) và "'"(\u{301}).
6. Control Flow:
- Sử dụng for, for-in, while, do-while cho vòng lặp.
- Dấu ngoặc đơn '()' trong câu lệnh điều kiện hoặc biến của vòng lặp là không bắt buộc, dấu ngoặc ôm '{}' xung quanh nội dung thì phải bắt buộc. Nhưng theo mình thì các bạn nên viết để cho câu lệnh dễ đọc.
let individualScores = [75, 43, 103, 87, 12]
var teamScore = 0
for score in individualScores {
if (score > 50) { //Valid - should use it
teamScore += 3
}
else {
teamScore += 1
}
}
println(teamScore)
let individualScores = [75, 43, 103, 87, 12]
var teamScore = 0
for score in individualScores {
if score > 50 { //Valid - should not use it.
teamScore += 3
}
else {
teamScore += 1
}
}
println(teamScore)
- Bạn có thể sử dụng if và let cùng với nhau, để kiểm tra biến là kiểu Optional.
var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
if let name = optionalName {
greeting = "Hello, \(name)"
}
println(greeting)
Nếu biến optionalName bằng nil thì sẽ in ra chữ 'Hello!'- Switch hỗ trợ bất kỳ loại dữ liệu và một loạt loại so sánh, switch sẽ tự động break vì thế không cần thêm từ khoá break trong mỗi case:
let vegetable = "red pepper"
switch vegetable {
case "celery":
let vegetableComment = "Add some raisins and make ants on a log."
case "cucumber", "watercress":
let vegetableComment = "That would make a good tea sandwich."
case let x where x.hasSuffix("pepper"):
let vegetableComment = "Is it a spicy \(x)?"
default:
let vegetableComment = "Everything tastes good in soup."
}
Bắt buộc phải có mệnh đề 'default', nếu không có sẽ bị lỗi.Chú ý: let được sử dụng trong một pattern để gán giá trị trùng khớp trong pattern để tạo thành hằng.
- Bạn có thể dùng for-in để duyệt qua những phần tử trong Dicitonary:
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 9, 16, 25],
]
var largest = 0
for (kind, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number
}
}
}
println(largest)
- Bạn có thể dùng "..<" và "..." trong vòng lặp for để tạo 1 khoảng những giá trị:
var firstForLoop = 0
for i in 0..<4 {
firstForLoop += i
}
println(firstForLoop)
var secondForLoop = 0
for var i = 0; i < 4; ++i {
secondForLoop += i
}
println(secondForLoop)
"..." bao gồm luôn giá trị đó, giống toán tử "<="
7. Functions and Closures:
func greet(name: String, day: String) -> String {
return "Hello \(name), today is \(day)."
}
greet("Bob", "Tuesday")
- Bạn có thể sử dụng một bộ (tuple) để tạo ra một giá trị ghép. Ví dụ bạn có thể trả về nhiều giá trị trong một hàm, bạn có thể truy xuất tuple thông qua tên (name) hoặc vị trí (index):
func calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
var min = scores[0]
var max = scores[0]
var sum = 0
for score in scores {
if score > max {
max = score
} else if score < min {
min = score
}
sum += score
}
return (min, max, sum)
}
let statistics = calculateStatistics([5, 3, 100, 3, 9])
println(statistics.sum)
println(statistics.2)
- Tham số là danh sách những giá trị (arguments) bạn có thể khai báo như sau:
func sumOf(numbers: Int...) -> Int {
var sum = 0
for number in numbers {
sum += number
}
return sum
}
sumOf()
sumOf(42, 597, 12)
- Bạn có thể khai báo những hàm lồng vào nhau (nested), nếu viết như vậy thì độ phức tạp của hàm sẽ bị tăng lên:
func returnFifteen() -> Int {
var y = 10
func add() {
y += 5
}
add()
return y
}
returnFifteen()
- Những hàm là kiểu first-class. Bạn có thể trả về tên hàm này trong một hàm khác như sau:
func makeIncrementer() -> (Int -> Int) {
func addOne(number: Int) -> Int {
return 1 + number
}
return addOne
}
var increment = makeIncrementer()
increment(7)
Hoặc bạn có thể truyền tên hàm như 1 tham số của hàm khác:
func hasAnyMatches(list: [Int], condition: Int -> Bool) -> Bool {
for item in list {
if condition(item) {
return true
}
}
return false
}
func lessThanTen(number: Int) -> Bool {
return number < 10
}
var numbers = [20, 19, 7, 12]
hasAnyMatches(numbers, lessThanTen)
- Functions là trường hợp đặc biệt của Closures (khối code). Code trong closure có thể truy xuất những thứ như những biến và hàm hợp lệ trong phạm vi mà closure đó được tạo, thậm chí ngay cả closure trong phạm vi khác nhau khi nó được thực hiện. Bạn có thể viết một closure mà không có tên, code được bao bọc bởi dấu ngoặc ôm (braces = {}). Chữ 'in' dùng để phân cách giữa tham số và kiểu trả về. Ví dụ:
var numbers = [20, 19, 7, 12]
let mappedNumbers =
numbers.map({
(number: Int) -> Int in
let result = 3 * number
return result
})
println(mappedNumbers)
Map là một hàm của array, bạn có thể xem thêm tại đây.Bạn có nhiều lựa chọn để viết những closure ngắn gọn và xúc tích. Khi kiểu dữ liệu của closure đã được biết bạn có thể bỏ chúng đi, code trên được viết lại như sau:
let mappedNumbers = numbers.map({ number in 3 * number }) println(mappedNumbers)
8. Objects and Classes:
class Shape {
var numberOfSides = 0
init(numberOfSides: Int) {
self.numberOfSides = numberOfSides
}
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
Cách sử dụng class:
var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()
- Bạn có thể viết kế thừa và hàm override như sau:
class Square: NamedShape {
var sideLength: Double
init(sideLength: Double, name: String) {
self.sideLength = sideLength
super.init(name: name)
numberOfSides = 4
}
func area() -> Double {
return sideLength * sideLength
}
override func simpleDescription() -> String {
return "A square with sides of length \(sideLength)."
}
}
let test = Square(sideLength: 5.2, name: "my test square")
test.area()
test.simpleDescription()
- Bạn có thể khai báo property như sau:
class EquilateralTriangle: NamedShape {
var sideLength: Double = 0.0
init(sideLength: Double, name: String) {
self.sideLength = sideLength
super.init(name: name)
numberOfSides = 3
}
var perimeter: Double {
get {
return 3.0 * sideLength
}
set {
sideLength = newValue / 3.0
}
}
override func simpleDescription() -> String {
return "An equilateral triangle with sides of length \(sideLength)."
}
}
var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
println(triangle.perimeter)
triangle.perimeter = 9.9
println(triangle.sideLength)
Lưu ý: biến newValue trong hàm set là mặc định. Bạn có thể đặt tên tham số khác bằng cách ghi tên biến đằng sau chữ 'set' trong dấu ngoặc đơn:set (value) {
sideLength = value / 3.0
}
- Bạn có thể dùng willSet và didSet trong property:
class TriangleAndSquare {
var triangle: EquilateralTriangle {
willSet {
square.sideLength = newValue.sideLength
}
}
var square: Square {
willSet {
triangle.sideLength = newValue.sideLength
}
}
init(size: Double, name: String) {
square = Square(sideLength: size, name: name)
triangle = EquilateralTriangle(sideLength: size, name: name)
}
}
var triangleAndSquare = TriangleAndSquare(size: 10, name: "another test shape")
println(triangleAndSquare.square.sideLength)
println(triangleAndSquare.triangle.sideLength)
triangleAndSquare.square = Square(sideLength: 50, name: "larger square")
println(triangleAndSquare.triangle.sideLength)
Bạn có thể xem thêm về Property tại đây.- Bạn có thể dùng giá trị optional bằng cách dùng ký hiệu '?' đằng trước những toán tử như methods, properties, and subscripting:
let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")
let sideLength = optionalSquare?.sideLength
Nếu bạn không chắc đối tượng đó có tồn tại hay không thì nên dùng cách này để truy xuất.
9. Enumerations and Structures:
- Sử dụng từ khoá 'enum' để tạo enumeration. Giống như class, enum có những hàm truy xuất trong nó:
enum Rank: Int {
case Ace = 1
case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
case Jack, Queen, King
func simpleDescription() -> String {
switch self {
case .Ace:
return "ace"
case .Jack:
return "jack"
case .Queen:
return "queen"
case .King:
return "king"
default:
return String(self.rawValue)
}
}
}
let ace = Rank.Ace
let aceRawValue = ace.rawValue
let jack = Rank.Jack
let jackRawValue = jack.simpleDescription()
enum Suit {
case Spades, Hearts, Diamonds, Clubs
func simpleDescription() -> String {
switch self {
case .Spades:
return "spades"
case .Hearts:
return "hearts"
case .Diamonds:
return "diamonds"
case .Clubs:
return "clubs"
}
}
}
let hearts = Suit.Hearts
let heartsDescription = hearts.simpleDescription()
- Sử dụng từ khoá 'struct' để khai báo một structure. Struct hỗ trợ nhiều hành động giống nhau như class, bao gồm những hàm (method) và những hàm khởi tạo (initializers). One of the most important differences between structures and classes is that structures are always copied when they are passed around in your code, but classes are passed by reference.struct Card {
var rank: Rank
var suit: Suit
func simpleDescription() -> String {
return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
}
}
let threeOfSpades = Card(rank: .Three, suit: .Spades)
let threeOfSpadesDescription = threeOfSpades.simpleDescription()
Cách so sánh giữa class và struct các bạn có thể tham khảo tại đây.
10. Protocols and Extensions:
- Dùng từ khoá 'protocol' để khai báo 1 protocol. Protocol trong ngôn ngữ Objective C và Swift giống như interface trong Java:
protocol ExampleProtocol {
var simpleDescription: String { get }
mutating func adjust()
}
- Những class, enumeration, và struct đều có thể nhận protocol:
class SimpleClass: ExampleProtocol {
var simpleDescription: String = "A very simple class."
var anotherProperty: Int = 69105
func adjust() {
simpleDescription += " Now 100% adjusted."
}
}
var a = SimpleClass()
a.adjust()
let aDescription = a.simpleDescription
struct SimpleStructure: ExampleProtocol {
var simpleDescription: String = "A simple structure"
mutating func adjust() {
simpleDescription += " (adjusted)"
}
}
var b = SimpleStructure()
b.adjust()
let bDescription = b.simpleDescription
enum SimpleEnumeration: ExampleProtocol {
case Base, Adjusted
var simpleDescription: String { get {
return self.getDescription()
}
}
func getDescription() -> String{
switch self{
case Base:
return "A simple description of enum"
case .Adjusted:
return "Adjusted description of enum"
default:
return "default description"
}
}
mutating func adjust() -> Void{
self = SimpleEnumeration.Adjusted
}
}
var c = SimpleEnumeration.Base
c.adjust()
let cDescription = c.simpleDescription
Lưu ý: từ khoá 'mutating' khai báo trước tên hàm cho biết hàm đó có thể thay đổi được, các bạn có thể xem thêm tại đây.- Sử dụng từ khoá 'extension' dùng để khai báo thêm những chức năng bạn muốn làm thêm cho những kiểu dữ liệu đã tồn tại trước đó.
extension Int: ExampleProtocol {
var simpleDescription: String {
return "The number \(self)"
}
mutating func adjust() {
self += 42
}
}
println(7.simpleDescription)
extension Double { var absoluteValue: Double { if (self < 0) { return self * -1 } return self } } var double: Double = -10 println(double.absoluteValue) //Print is 10.0
11. Generics:
- Viết tên bên trong ngoặc nhọn (angle brackets, < >), để tạo generic function hay kiểu dữ liệu:
func repeat<Item>(item: Item, times: Int) -> [Item] {
var result = [Item]()
for i in 0..<times {
result.append(item)
}
return result
}
var result = repeat("knock", 4)
println(result)
- Bạn có thể tạo generic trên functions, methods, classes, enumerations, và structures:
// Reimplement the Swift standard library's optional type
enum OptionalValue<T> {
case None
case Some(T)
}
var possibleInteger: OptionalValue<Int> = .None
possibleInteger = .Some(100)
- Sử dụng từ khoá 'where' sau tên của kiểu chỉ định một danh sách bắt buộc.
func anyCommonElements <T, U where T: SequenceType, U: SequenceType, T.Generator.Element: Equatable, T.Generator.Element == U.Generator.Element> (lhs: T, rhs: U) -> Bool { for lhsItem in lhs { for rhsItem in rhs { if lhsItem == rhsItem { return true } } } return false } anyCommonElements([1, 2, 3], [3])
- Kiểm tra loại device:
Tài liệu tham khảo:
- Apple Swift Documents.
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.