ตอนที่ 7 iOS Swift แนวคิด Swift ขั้นสูง (Advanced Swift Concepts)

  1. ตัวห่อหุ้มคุณสมบัติ (Property wrappers) และคุณสมบัติที่คำนวณได้ (computed properties)
  2. ตัวดำเนินการแบบกำหนดเอง (Custom operators) และการโอเวอร์โหลดตัวดำเนินการ (operator overloading)
  3. Generics และประเภทที่เกี่ยวข้อง (associated types)
  4. Swift Metaprogramming และการสะท้อนกลับ (reflection)

Swift เป็นภาษาสำหรับการรับทำแอพที่ทรงพลังและใช้งานง่ายที่พัฒนาโดย Apple สำหรับทำแอพ iOS, macOS, watchOS และการทำแอพ tvOS เป็นที่รู้จักในด้านไวยากรณ์ที่สื่อความหมายและคุณสมบัติด้านความปลอดภัย ในบทความนี้ เราจะสำรวจแนวคิดขั้นสูงของ iOS Swift เพื่อช่วยให้คุณเขียนโค้ดที่สะอาดขึ้น มีประสิทธิภาพมากขึ้น และบำรุงรักษาได้ เราจะครอบคลุมถึงตัวห่อหุ้มคุณสมบัติ (Property wrappers) คุณสมบัติที่คำนวณ (computed properties) ตัวดำเนินการแบบกำหนดเอง (Custom operators) ข้อมูลทั่วไป และโปรแกรมเมตาดาต้า (Metaprogramming) และการสะท้อนกลับ (reflection) ของ Swift

1. ตัวห่อหุ้มคุณสมบัติ (Property wrappers) และคุณสมบัติที่คำนวณได้ (computed properties)

ตัวห่อหุ้มคุณสมบัติ (Property wrappers) เป็นคุณสมบัติใน iOS Swift ที่ให้คุณสรุปตรรกะสำหรับการรับและตั้งค่าคุณสมบัติ สิ่งนี้สามารถช่วยลดโค้ดสำเร็จรูปและปรับปรุงการอ่านโค้ด Wrapper คุณสมบัติคือแอตทริบิวต์แบบกำหนดเองที่คุณสามารถนำไปใช้กับคุณสมบัติได้ และถูกกำหนดโดยการสร้างชนิดใหม่ที่ล้อมรอบคุณสมบัติและปรับใช้เมธอดเฉพาะ

ในการสร้าง wrapper คุณสมบัติ คุณต้องกำหนด struct, class หรือ enum ด้วยแอตทริบิวต์@propertyWrapper เฉพาะ wrapper ต้องมี wrappedValue คุณสมบัติที่กำหนดตรรกะของ get และ set

@propertyWrapper
struct Capitalized {
    private(set) var value: String = ""

    var wrappedValue: String {
        get { value }
        set { value = newValue.capitalized }
    }
}

ในตัวอย่างข้างต้น เราสร้าง Capitalized ตัวตัดคุณสมบัติที่ทำให้สตริงที่กำหนดเป็นตัวพิมพ์ใหญ่ หากต้องการใช้ wrapper คุณสมบัติ เพียงใช้แอตทริบิวต์ที่กำหนดเองกับคุณสมบัติ:

struct User {
    @Capitalized var name: String
}

ในทางกลับกัน คุณสมบัติที่คำนวณได้จะไม่เก็บค่า แต่จะจัดเตรียม getter และ setter ที่เป็นทางเลือกเพื่อคำนวณค่า คุณสมบัติเหล่านี้มีประโยชน์สำหรับการห่อหุ้มการคำนวณหรือตรรกะตามคุณสมบัติอื่นๆ

struct Circle {
    var radius: Double
    
    var circumference: Double {
        get {
            return 2 * Double.pi * radius
        }
        set {
            radius = newValue / (2 * Double.pi)
        }
    }
}

ในตัวอย่างนี้ เรากำหนด Circleโครงสร้างด้วยคุณสมบัติที่คำนวณ circumference ได้ เมื่อคุณได้เส้นรอบวง ระบบจะคำนวณตามรัศมี เมื่อคุณตั้งค่าเส้นรอบวง ระบบจะอัปเดตรัศมีตามนั้น

2. ตัวดำเนินการแบบกำหนดเอง (Custom operators) และการโอเวอร์โหลดตัวดำเนินการ (operator overloading)

Swift อนุญาตให้คุณกำหนดตัวดำเนินการแบบกำหนดเองและโอเวอร์โหลดตัวดำเนินการที่มีอยู่เพื่อให้การทำงานแบบกำหนดเองสำหรับประเภทของคุณ สิ่งนี้สามารถช่วยให้โค้ดของคุณแสดงออกและเข้าใจได้ง่ายยิ่งขึ้น

ในการกำหนดโอเปอเรเตอร์แบบกำหนดเอง คุณต้องประกาศโดยใช้ operator คำหลักและระบุการเชื่อมโยงและกลุ่มลำดับความสำคัญ จากนั้น คุณต้องใช้ฟังก์ชันสากลที่มีตัวดำเนินการเป็นชื่อฟังก์ชัน

infix operator **: ExponentiationPrecedence

func **(lhs: Double, rhs: Double) -> Double {
    return pow(lhs, rhs)
}

ในตัวอย่างนี้ เรากำหนดตัวดำเนินการแบบกำหนดเอง**สำหรับการยกกำลัง เราระบุกลุ่มความเชื่อมโยงและลำดับความสำคัญ และใช้ฟังก์ชันสากลเพื่อดำเนินการยกกำลังโดยใช้ pow ฟังก์ชัน ของไลบรารีมาตรฐาน

คุณยังสามารถโอเวอร์โหลดโอเปอเรเตอร์ที่มีอยู่เพื่อจัดเตรียมฟังก์ชันการทำงานแบบกำหนดเองสำหรับประเภทของคุณ:

struct Vector {
    var x: Double
    var y: Double
}

func +(lhs: Vector, rhs: Vector) -> Vector {
    return Vector(x: lhs.x + rhs.x, y: lhs.y + rhs.y)
}

ที่นี่ เราสร้างVectorโครงสร้างและโอเวอร์โหลด+ตัวดำเนินการเพื่อเพิ่มเวกเตอร์สองตัว

3. Generics และประเภทที่เกี่ยวข้อง (associated types)

Generics ช่วยให้คุณสามารถทำแอพที่ยืดหยุ่นและใช้ซ้ำได้ซึ่งสามารถทำงานได้ด้วยประเภทข้อมูลที่แตกต่างกันโดยยังคงรักษาความปลอดภัยของประเภทไว้ ด้วยข้อมูลทั่วไป คุณสามารถสร้างฟังก์ชัน โครงสร้าง และคลาสที่สามารถทำงานกับประเภทใดก็ได้ โดยระบุเป็นตัวยึดตำแหน่ง

struct Stack<Element> {
    private var items: [Element] = []

    mutating func push(_ item: Element) {
        items.append(item)
    }

    mutating func pop() -> Element? {
        return items.popLast()
    }
}

ในตัวอย่างนี้ เราสร้าง Stack โครงสร้างทั่วไปที่ทำงานกับข้อมูลประเภทใดก็ได้ ประเภททั่วไประบุโดยใช้วงเล็บมุม <Element>

ประเภทที่เกี่ยวข้องเป็นวิธีกำหนดประเภทตัวยึดในโปรโตคอล มีการระบุประเภทเหล่านี้เมื่อใช้โปรโตคอล ช่วยให้คุณสร้างโปรโตคอลที่สามารถทำงานกับหลายประเภทในขณะที่รักษาความปลอดภัยของประเภท

protocol Container {
    associatedtype Item

    mutating func append(_ item: Item)
    var count: Int { get }
    subscript(i: Int) -> Item { get }
}

ในตัวอย่างนี้ เราสร้าง Container โปรโตคอลที่มีประเภทที่เกี่ยวข้อง Item กัน ประเภทใดก็ตามที่เป็นไปตามโปรโตคอลนี้ต้องระบุประเภท Item และดำเนินการตามวิธีการและคุณสมบัติที่จำเป็น

4. Swift Metaprogramming และการสะท้อนกลับ (reflection)

การเขียนโปรแกรมเมตาเป็นเทคนิคการเขียนโปรแกรมที่ทำให้โปรแกรมสามารถสร้าง วิเคราะห์ หรือแปลงโค้ดได้ iOS Swift มีความสามารถในการโปรแกรมเมตาที่จำกัดผ่านการใช้การสะท้อนกลับ

การสะท้อนคือความสามารถในการตรวจสอบคุณสมบัติและวิธีการของอินสแตนซ์ในขณะรันไทม์ ใน Swift คุณสามารถใช้ Mirror ประเภทเพื่อสะท้อนกับอินสแตนซ์

struct Person {
    let name: String
    let age: Int
}

let person = Person(name: "Alice", age: 30)
let mirror = Mirror(reflecting: person)

for child in mirror.children {
    print("\(child.label ?? "unknown"): \(child.value)")
}

ในตัวอย่างนี้ เราสร้าง Person โครงสร้างและใช้ Mirror ประเภทเพื่อสะท้อนถึงอินสแตนซ์ Person ของ จากนั้นเราวนลูปผ่าน children คุณสมบัติของ Mirror อินสแตนซ์เพื่อเข้าถึงคุณสมบัติของ Person อินสแตนซ์

โปรดทราบว่าความสามารถในการสะท้อนของ iOS Swift มีจำกัดเมื่อเทียบกับภาษาอื่นบางภาษา และการใช้การสะท้อนกลับจำนวนมากอาจส่งผลเสียต่อประสิทธิภาพและความปลอดภัยของโค้ด ใช้เท่าที่จำเป็นและเมื่อจำเป็นเท่านั้น

แนวคิด iOS Swift ขั้นสูงสำหรับการทำแอพ เช่น wrapper คุณสมบัติ คุณสมบัติจากการคำนวณ ตัวดำเนินการแบบกำหนดเอง generics และ metaprogramming ช่วยให้ทำแอพที่สะอาดขึ้น แสดงออกมากขึ้น และบำรุงรักษาได้ คุณสามารถใช้คุณสมบัติอันทรงพลังของ Swift เพื่อทำแอพที่แข็งแกร่งและมีประสิทธิภาพสำหรับแพลตฟอร์มของ Apple โดยการใช้แนวคิดเหล่านี้จนเชี่ยวชาญ โปรดทราบว่าเทคนิคบางอย่างอาจมีการแลกเปลี่ยน เช่น ประสิทธิภาพหรือผลกระทบด้านความปลอดภัย ดังนั้นควรพิจารณากรณีการใช้งานเฉพาะก่อนที่จะนำไปใช้ในในการรับทำแอพ

เขียน App iOS Swift

ตอนที่ 6 iOS Swift ตัวเลือก (Optionals) และการจัดการข้อผิดพลาด (Error Handling)
ตอนที่ 8 iOS Swift การทำงานพร้อมกัน (Concurrency)