Bài 25: Extensions trong swift - Lập trình Swift cơ bản

Đăng bởi: Admin | Lượt xem: 2285 | Chuyên mục: Swift


Khái niệm 

Extensions là một tính năng mới có khả năng mở rộng để thêm các hàm hoặc các Properties mới cho Class, Struct , Enumeration hoặc Protocol.
Extension có khả năng:
  • Thêm và tạo mới các instance Properties hoặc Type Properties
  • Định nghĩa các instance methods hoặc type methods
  • Định nghĩa hàm khởi tạo mới
  • Định nghĩa subscripts
  • Sử dụng các nested type
  • Thực hiện các phương thức của protocol

Cú pháp(Syntax)

Chúng ta sẽ dùng từ khóa extension để mô tả các extensions khác nhau 
Bạn có thể tham khảo ví dụ dưới đây:
extension SomeType {

   // Chúng ta có thể thêm các hàm hoặc thuộc tính mới ở đây.

}
Ở ví dụ này, extension cũng giống như class, struct là có thể chấp nhận một hay nhiều protocol trong cùng một đoạn code
Bạn có thể tham khảo ví dụ dưới đây:
extension SomeType: SomeProtocol, AnotherProtocol {

   // Chúng ta có thể implement các method của các protocol ở đây hoặc thêm hàm, thuộc tính mới

}
Một lưu ý nữa là bạn hoàn toàn có thể định nghĩa hàm hoặc properties mới cho bất kỳ loại dữ liệu nào nhờ vào extension và tất nhiên khi đó chúng sẽ có mặt trong tất cả các instances của kiểu dữ liệu đó.

Tính năng

Computed Properties

Extension cho phép bạn thêm thuộc tính về tính toán  (computed instance properties) và (computed type properties) vào các kiểu dữ liệu đã được định nghĩa sẵn.
Xem ví dụ dưới đây để hiểu rõ hơn nhé
extension Double {
   var km: Double { return self * 1_000.0 }
   var m: Double { return self }
   var cm: Double { return self / 100.0 }
   var mm: Double { return self / 1_000.0 }
   var ft: Double { return self / 3.28084 }
}
let oneInch = 25.4.mm
print("One inch is \(oneInch) meters")
// Prints "One inch is 0.0254 meters"
let threeFeet = 3.ft
print("Three feet is \(threeFeet) meters")
// Prints "Three feet is 0.914399970739201 meters"
Ví dụ về extension thêm các thuộc tính(computed properties type):
extension Double {
   static var meters = 50
}

print("meters = \(Double.meters)")

extension UserDefaults {
  class var passwordKey:String {
    return "Tự học Swift 5.0"
  }
}

print("print key: \(UserDefaults.passwordKey)")
Khi dùng computed properties type  bạn hoàn toàn có thể gọi trực tiếp tên đối tượng thay vì tạo mới chúng.
Lưu ý: Extension không thể khởi tạo một thuộc tính mới khi thuộc tính đó đã chứa một giá trị nào đó. Và Xcode sẽ báo lỗi nếu chúng ta cố gắng khởi tạo.
Bạn có thể xem thêm ví dụ dưới đây để hiểu hơn nhé
extension Double {
    var x = 10
    var y = 10
}

Initialization

Bạn có thể xem thêm ví dụ dưới đây để hiểu hơn nhé
struct Size {

   var width = 0.0, height = 0.0

}

struct Point {

   var x = 0.0, y = 0.0

}

struct Rect {

   var origin = Point()

   var size = Size()

}
Sử dụng hàm khởi tạo mặc định của struct trên như sau:
let defaultRect = Rect()

let memberwiseRect = Rect(origin: Point(x: 2.0, y: 2.0), 

                            size: Size(width: 5.0, height: 5.0))
Và lúc này đây, bạn có thể extension thêm hàm khởi tạo cho struct mà không lo bị lỗi như sau:
extension Rect {

   init(center: Point, size: Size) {

       let originX = center.x - (size.width / 2)

       let originY = center.y - (size.height / 2)

       self.init(origin: Point(x: originX, y: originY), size: size)

   }

}
Và sử dụng nó:
let centerRect = Rect(center: Point(x: 4.0, y: 4.0),

                     size: Size(width: 3.0, height: 3.0))

// centerRect's origin is (2.5, 2.5) and its size is (3.0, 3.0)

Method

Khi extension thêm instance method.
extension Int {

   func repetitions(task: () -> Void) {

       for _ in 0..<self {

           task()

       }

   }

}

3.repetitions {

   print("Hello!")

}

// Hello!

// Hello!

// Hello!
Instance method là hàm dùng để xử lý một cái gì đó nhưng nó dùng chính bản thân đối tượng gọi hàm đó để xử lý. như ví dụ trên chúng ta sẽ thấy số 3 sử dụng hàm repetitions và trong hàm đó sẽ dùng chính số 3 trong việc in ra chữ Hello! 3 lần.
Ví dụ về extension thêm type method.
struct Point {

    var x = 0.0

    var y = 0.0

    static func closestToOrigin(p1: Point, _ p2: Point) -> Point {

        let p1Distance = p1.distanceFromOrigin()

        let p2Distance = p2.distanceFromOrigin()

        if p1Distance < p2Distance {

            return p1

        } else {

            return p2

        }

    }

    func distanceFromOrigin() -> Double {

        return sqrt((x*x)+(y*y))

    }

}

let firstPoint = Point(x: 1.5, y: 3.9)

let secondPoint = Point(x: 49.2, y: 15.9)

let answer = Point.closestToOrigin(firstPoint, secondPoint)

answer.x    //Returns 1.5

answer.y    //Returns 3.9
Ở ví dụ trên bạn có thể thấy hàm closestToOrigin là một type method và nó được gọi trực tiếp Object Point thay vì tạo mới object Point rồi mới gọi 
Có thể extension mutating instance method
Bạn có thể xem thêm ví dụ dưới đây để hiểu hơn nhé
extension Int {

   mutating func square() {

       self = self * self

   }

}

var someInt = 3

someInt.square()

// someInt is now 9

Subscripts

Subscripts có nhiệm vụ giúp truy xuất dữ liệu nhanh chóng hơn và chúng ta có thể thêm subscript cho một kiểu dữ liệu nào đó đã được định nghĩa.
Ví dụ về extension Int:
extension Int {

   subscript(digitIndex: Int) -> Int {

       var decimalBase = 1

       for _ in 0..<digitIndex {

           decimalBase *= 10

       }

       return (self / decimalBase) % 10

   }

}

746381295[0]

// returns 5

746381295[1]

// returns 9

746381295[2]

// returns 2

746381295[8]

// returns 7

Nested Types

Nested types là tạo ra một dữ liệu mới được lồng sẵn trong một dữ liệu khác.
Bạn có thể xem thêm ví dụ dưới đây để hiểu hơn nhé
extension Int {

   enum Kind {

       case negative, zero, positive

   }

   var kind: Kind {

       switch self {

       case 0:

           return .zero

       case let x where x > 0:

           return .positive

       default:

           return .negative

       }

   }

}
Sử dụng như sau:
func printIntegerKinds(_ numbers: [Int]) {

   for number in numbers {

       switch number.kind {

       case .negative:

           print("- ", terminator: "")

       case .zero:

           print("0 ", terminator: "")

       case .positive:

           print("+ ", terminator: "")

       }

   }

   print("")

}

printIntegerKinds([3, 19, -27, 0, -6, 0, 7])

// Prints "+ + - 0 - 0 + "
Bài tiếp theo: Protocols trong swift >>
vncoder logo

Theo dõi VnCoder trên Facebook, để cập nhật những bài viết, tin tức và khoá học mới nhất!