Bài 18: Methods trong swift – Lập trình Swift cơ bản

Trang chủ » Training » Bài 18: Methods trong swift – Lập trình Swift cơ bản
01/03/2022 Training 114 viewed
Phương thức là các hàm được liên kết với một loại cụ thể. Các lớp, cấu trúc và bảng liệt kê đều có thể định nghĩa các phương thức cá thể, gói gọn các tác vụ và chức năng cụ thể để làm việc với một hàm của một kiểu đã cho.
Các lớp, cấu trúc và bảng liệt kê cũng có thể định nghĩa các phương thức kiểu, được liên kết với chính kiểu đó. Các phương thức kiểu tương tự như các phương thức lớp trong Objective-C.
Thực tế là các cấu trúc và bảng liệt kê có thể định nghĩa các phương thức trong Swift là một sự khác biệt lớn so với C và Objective-C. Trong Objective-C, các lớp là các dạng duy nhất có thể định nghĩa các phương thức. Trong Swift, bạn có thể chọn xác định một lớp, cấu trúc hoặc liệt kê và vẫn có thể linh hoạt để xác định các phương thức trong dạng mà bạn tạo.

Instance Methods

Instance Methods là các hàm thuộc về instances  của một lớp, cấu trúc hoặc kiểu liệt kê cụ thể. Chúng hỗ trợ chức năng của các instances  đó, bằng cách cung cấp các cách để truy cập và sửa đổi các thuộc tính thể hiện hoặc bằng cách cung cấp chức năng liên quan đến mục đích của instances . .
Một Instance Method có quyền truy cập ngầm vào tất cả các phương thức và thuộc tính khác của loại đó. Một instance method chỉ có thể được gọi trên một instance cụ thể của loại mà nó thuộc về.
Dưới đây là một ví dụ xác định một Counterlớp đơn giản , có thể được sử dụng để đếm số lần xảy ra một hành động:
Các Counter class định nghĩa ba phương pháp dụ:
  • increment()tăng bộ đếm bằng 1.
  • increment(by: Int) tăng bộ đếm bằng một số nguyên xác định.
  • reset()  đặt lại bộ đếm về không.
Các  Counter class cũng tuyên bố một tài sản thay đổi, count để theo dõi các giá trị truy cập hiện tại.
Bạn gọi các phương thức cá thể có cú pháp dấu chấm giống như các thuộc tính:
let counter = Counter()

// the initial counter value is 0

counter.increment()

// the counter's value is now 1

counter.increment(by: 5)

// the counter's value is now 6

counter.reset()
  • // the counter’s value is now 0

The self Property

Mỗi phiên bản của một loại có một thuộc tính ẩn được gọi là self, chính xác tương đương với chính instance đó. Bạn sử dụng self Property để tham chiếu đến các  instance  hiện tại trong các phương thức cá thể của chính nó.
Phương pháp increment() trong ví dụ trên có thể được viết như thế này:
func increment() {

   self.count += 1

}
Trong thực tế, bạn không cần phải viết self trong code của bạn. Nếu bạn không viết rõ ràng self, Swift giả định rằng bạn đang đề cập đến một thuộc tính hoặc phương thức của thể hiện hiện tại bất cứ khi nào bạn sử dụng một thuộc tính hoặc tên phương thức đã biết trong một phương thức. Giả định này được thể hiện bằng cách sử dụng count(chứ không phải self.count) bên trong ba phương thức thể hiện cho Counter.
Ngoại lệ chính cho quy tắc này xảy ra khi tên của 1 tham số cho một phương thức cá thể cùng tên với một thuộc tính của cá thể đó. Trong tình huống này, tên tham số được ưu tiên và cần tham chiếu đến thuộc tính theo cách phức tạp hơn. Bạn sử dụng thuộc  self Property để phân biệt giữa tên tham số và tên thuộc tính.
Ở đây, self phân biệt giữa một tham số phương thức được gọi x là một thuộc tính cá thể cũng được gọi là x:
struct Point {  
  var x = 0.0, 
  y = 0.0 

  func isToTheRightOf(x: Double) -> Bool {     
      return self.x > x   }
  }

  let somePoint = Point(x: 4.0, y: 5.0)if somePoint.isToTheRightOf(x: 1.0) {

      print("This point is to the right of the line where x == 1.0")

  }// Prints "This point is to the right of the line where x == 1.0"
}
Nếu không có self tiền tố, Swift sẽ cho rằng cả hai cách sử dụng tham chiếu phương thức được gọi x.

Modifying Value Types from Within Instance Methods

Cấu trúc và liệt kê là các loại giá trị . Theo mặc định, các thuộc tính của một loại giá trị không thể được sửa đổi từ bên trong các phương thức thể hiện của nó.
Tuy nhiên, nếu bạn cần sửa đổi các thuộc tính của cấu trúc hoặc bảng liệt kê trong một phương thức cụ thể, bạn có thể thay đổi thuộc tính cho phương thức đó. Phương thức sau đó có thể biến đổi các thuộc tính của nó từ bên trong phương thức và mọi thay đổi mà nó thực hiện được ghi lại vào cấu trúc ban đầu khi phương thức kết thúc.
Phương thức cũng có thể gán một instance hoàn toàn mới cho thuộc tính ẩn của self property và  instance  mới này sẽ thay thế một thể hiện có khi phương thức kết thúc.
struct Point {

   var x = 0.0, y = 0.0

   mutating func moveBy(x deltaX: Double, y deltaY: Double) {

       x += deltaX

       y += deltaY

   }

}

var somePoint = Point(x: 1.0, y: 1.0)

somePoint.moveBy(x: 2.0, y: 3.0)

print("The point is now at (\(somePoint.x), \(somePoint.y))")
  • // Prints “The point is now at (3.0, 4.0)”
Các cấu trúc Point ở trên định nghĩa một biến đổi phương pháp moveBy(x:y:), trong đó di chuyển một Point của một số lượng nhất định.
Lưu ý rằng bạn không thể gọi một phương thức đột biến trên hằng số loại cấu trúc, bởi vì các thuộc tính của nó không thể thay đổi, ngay cả khi chúng là các thuộc tính biến.
let fixedPoint = Point(x: 3.0, y: 3.0)

fixedPoint.moveBy(x: 2.0, y: 3.0)
  • // this will report an error

Mutating Method

Mutating methods có thể gán một instance hoàn toàn mới cho thuộc tính ẩn self. Đối với  Point  được trình bày ở trên có thể được viết theo cách sau thay vì:
Phiên bản của phương thức moveBy(x:y:) đột biến này tạo ra một cấu trúc mới có giá trị và giá trị được đặt thành vị trí đích. Kết quả cuối cùng của việc gọi phiên bản thay thế này của phương thức sẽ hoàn toàn giống với cách gọi phiên bản trước đó.
Các phương thức gây đột biến cho liệt kê có thể đặt self  tham số ngầm là một trường hợp khác với cùng một kiểu liệt kê:
enum TriStateSwitch {

   case off, low, high

   mutating func next() {

       switch self {

       case .off:

           self = .low

       case .low:

           self = .high

       case .high:

           self = .off

       }

   }

}

var ovenLight = TriStateSwitch.low

ovenLight.next()

// ovenLight is now equal to .high

ovenLight.next()

// ovenLight is now equal to .off
Ví dụ này xác định một bảng liệt kê cho một chuyển đổi ba trạng thái. Các chu kỳ chuyển đổi giữa ba trạng thái khác nhau điện ( off, low và high) mỗi khi nó next() phương pháp được gọi.

Type Methods

Đối với Instance methods, như được mô tả ở trên, là các phương thức mà bạn gọi trên một thể hiện của một dạng cụ thể. Bạn cũng có thể định nghĩa các phương thức được gọi trên chính kiểu đó. Những loại phương thức này được gọi là  type methods . Bạn chỉ ra các phương thức loại bằng cách viết static từ khóa trước từ khóa của method func.
Type methods được gọi với cú pháp dấu chấm, giống như  instance methods. Tuy nhiên, bạn gọi các type methods  trên các dạng mà  không phải trên một instance  của dạng  đó. Đây là cách bạn gọi một phương thức kiểu trên một lớp được gọi là SomeClass:
class SomeClass {

   class func someTypeMethod() {

       // type method implementation goes here

   }

}

SomeClass.someTypeMethod()
Ví dụ dưới đây xác định cấu trúc được gọi LevelTracker, theo dõi tiến trình của người chơi thông qua các cấp hoặc giai đoạn khác nhau của trò chơi. Đây là một trò chơi một người chơi, nhưng có thể lưu trữ thông tin cho nhiều người chơi trên một thiết bị.
Tất cả các cấp của trò chơi (ngoài cấp một) đều bị khóa khi trò chơi được chơi lần đầu tiên. Mỗi khi người chơi hoàn thành một cấp độ, cấp độ đó sẽ được mở khóa cho tất cả người chơi trên thiết bị. Các LevelTracker cấu trúc sử dụng thuộc tính loại và phương pháp để theo dõi trong đó nồng độ của trò chơi đã được mở khóa. Nó cũng theo dõi cấp độ hiện tại cho một người chơi cá nhân.
struct LevelTracker {
   static var highestUnlockedLevel = 1
   var currentLevel = 1
   static func unlock(_ level: Int) {
       if level > highestUnlockedLevel { highestUnlockedLevel = level }
   }
   static func isUnlocked(_ level: Int) -> Bool {
       return level <= highestUnlockedLevel
   }
   @discardableResult
   mutating func advance(to level: Int) -> Bool {
       if LevelTracker.isUnlocked(level) {
           currentLevel = level
           return true
       } else {
           return false
       }
   }
}
Các LevelTracker cấu trúc theo dõi mức độ cao nhất mà bất kỳ người chơi đã mở khóa. Giá trị này được lưu trữ trong một thuộc tính loại được gọi là highestUnlockedLevel.
LevelTracker cũng định nghĩa hai loại hàm để làm việc với thuộc tính  highestUnlockedLevel. Đầu tiên là một hàm loại được gọi unlock(_:), cập nhật giá trị của highestUnlockedLevelbất cứ khi nào một cấp độ mới được mở khóa. Thứ hai là một hàm loại tiện lợi được gọi  isUnlocked(_:), sẽ trả về true nếu một số cấp cụ thể đã được mở khóa. (Lưu ý rằng các phương thức loại này có thể truy cập thuộc tính highestUnlockedLevelmà bạn không cần phải viết nó dưới dạng LevelTracker .highestUnlockedLevel.)
Ngoài các phương thức loại và thuộc tính loại, LevelTracker theo dõi tiến trình của từng người chơi thông qua trò chơi. Nó sử dụng một thuộc tính thể hiện được gọi currentLevel để theo dõi cấp độ mà người chơi hiện đang chơi.
Để giúp quản lý currentLevel tài sản, LevelTracker xác định một phương thức thể hiện được gọi là advance(to:). Trước khi cập nhật currentLevel, phương pháp này kiểm tra xem mức độ mới được yêu cầu đã được mở khóa chưa. Các phương thức advance(to:) trả về một giá trị Boolean để cho biết hay không nó đã thực sự có khả năng thiết lập currentLevel. Vì không nhất thiết là lỗi mã gọi phương thức  advance(to:) bỏ qua giá trị trả về, nên hàm này được đánh dấu bằng @discardableResult .
Các LevelTracker cấu trúc được sử dụng với các Player class, trình bày dưới đây, để theo dõi và cập nhật tiến độ của một cầu thủ cá nhân:
class Player {
   var tracker = LevelTracker()
   let playerName: String
   func complete(level: Int) {
       LevelTracker.unlock(level + 1)
       tracker.advance(to: level + 1)
   }
   init(name: String) {
       playerName = name
   }
}
Các Player class tạo ra một thể hiện mới của LevelTracker để theo dõi sự tiến bộ của người chơi đó. Nó cũng cung cấp một phương thức được gọi  complete(level:), được gọi bất cứ khi nào người chơi hoàn thành một cấp độ cụ thể.
Phương pháp này mở ra cấp độ tiếp theo cho tất cả người chơi và cập nhật tiến trình của người chơi để chuyển họ sang cấp độ tiếp theo. (Giá trị trả về Boolean của advance(to:)bị bỏ qua, vì mức được biết là đã được mở khóa bằng lệnh gọi đến LevelTracker.unlock(_:)trên dòng trước đó.)
Bạn có thể tạo một thể hiện của Player class  cho một người chơi mới và xem điều gì sẽ xảy ra khi người chơi hoàn thành cấp độ một:
var player = Player(name: "Argyrios")

player.complete(level: 1)

print("highest unlocked level is now \(LevelTracker.highestUnlockedLevel)")

// Prints "highest unlocked level is now 2"
Nếu bạn tạo một người chơi thứ hai, người mà bạn cố gắng di chuyển đến một cấp độ chưa được mở khóa bởi bất kỳ người chơi nào trong trò chơi, thì nỗ lực đặt cấp độ hiện tại của người chơi sẽ thất bại:
player = Player(name: "Beto")
if player.tracker.advance(to: 6) {
   print("player is now on level 6")
} else {
   print("level 6 has not yet been unlocked")
}
// Prints "level 6 has not yet been unlocked"
Chia sẻ:
Tags:
TOP HOME