KeyPath ที่เขียนได้และอ้างอิงได้
อ่านและเขียนผ่านเส้นทางคีย์
KeyPath ที่เขียนได้และอ้างอิงได้ เป็นบทเรียน Swift Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Swift Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Swift Academy มีบทเรียนทั้งหมด 4 บทเรียน
คีย์พาธแบบอ่านอย่างเดียวเทียบกับแบบเขียนได้
KeyPath ธรรมดาใช้ read ค่าได้เท่านั้น หากต้องการเขียนค่าผ่านคีย์พาธ คุณต้องใช้รูปแบบที่เขียนได้ Swift มีรูปแบบดังกล่าวสองชนิด ชนิดหนึ่งสำหรับชนิดค่า และอีกชนิดหนึ่งสำหรับชนิดอ้างอิง
บทเรียนนี้ครอบคลุม WritableKeyPath สำหรับโครงสร้างข้อมูลและ ReferenceWritableKeyPath สำหรับคลาส รวมถึงวิธีที่ซับสคริปต์ [keyPath:] กลายเป็นสิ่งที่กำหนดค่าได้
struct Person {
var name: String
var age: Int
}
let writable: WritableKeyPath<Person, Int> = \Person.age
print(type(of: writable))WritableKeyPath สำหรับชนิดค่า
WritableKeyPath ใช้ชี้ไปยังคุณสมบัติที่จัดเก็บและเปลี่ยนแปลงได้ของชนิดค่า หากต้องการกำหนดค่าผ่านคีย์พาธ อินสแตนซ์นั้นต้องเป็น var เพราะการเปลี่ยนคุณสมบัติของโครงสร้างข้อมูลจะเปลี่ยนค่าทั้งหมด
ใช้ซับสคริปต์ [keyPath:] ทางด้านซ้ายของการกำหนดค่าเพื่อเขียนค่า
struct Person {
var name: String
var age: Int
}
var alice = Person(name: "Alice", age: 30)
let agePath = \Person.age
alice[keyPath: agePath] = 31
print(alice.age)เหตุใดอินสแตนซ์จึงต้องเป็น var
สำหรับชนิดค่า การเขียนผ่านคีย์พาธจะเปลี่ยนสำเนาค่าเดิมโดยตรง หากอินสแตนซ์เป็น let ก็ไม่มีสิ่งใดให้เปลี่ยนแปลง ดังนั้นการกำหนดค่าจะคอมไพล์ไม่ผ่าน
กฎนี้เหมือนกับการเปลี่ยนคุณสมบัติตามปกติ คุณจะกำหนดค่าคุณสมบัติที่จัดเก็บของโครงสร้างข้อมูลได้ก็ต่อเมื่อโครงสร้างข้อมูลนั้นถูกเก็บไว้ในตัวแปร
struct Point {
var x: Int
var y: Int
}
var p = Point(x: 1, y: 2)
p[keyPath: \Point.x] = 10
p[keyPath: \Point.y] = 20
print(p)ตัวช่วยกำหนดค่าแบบทั่วไป
เนื่องจากคีย์พาธแบบเขียนได้เก็บข้อมูลว่าต้องเปลี่ยนคุณสมบัติใด คุณจึงเขียนฟังก์ชันทั่วไปที่อัปเดตคุณสมบัติใดก็ได้ของชนิดค่าใดก็ได้ ส่งอินสแตนซ์ด้วย inout เพื่อให้การเปลี่ยนแปลงถูกเขียนกลับไป
นี่คือพื้นฐานของเครื่องมือขนาดเล็กสำหรับการอัปเดตแบบฟังก์ชัน
func update<Root, Value>(_ root: inout Root, _ path: WritableKeyPath<Root, Value>, to value: Value) {
root[keyPath: path] = value
}
struct Person { var name: String; var age: Int }
var bob = Person(name: "Bob", age: 40)
update(&bob, \.age, to: 41)
print(bob.age)ReferenceWritableKeyPath สำหรับคลาส
สำหรับคลาส Swift มี ReferenceWritableKeyPath ให้ใช้ เนื่องจากอินสแตนซ์ของคลาสเป็นการอ้างอิง คุณจึงเขียนค่าผ่านอินสแตนซ์ได้แม้อินสแตนซ์นั้นจะถูกเก็บไว้ในค่าคงที่ let การอ้างอิงไม่ได้เปลี่ยนแปลง มีเพียงอ็อบเจ็กต์ที่การอ้างอิงชี้ไปเท่านั้นที่เปลี่ยน
นี่คือความแตกต่างสำคัญจากคีย์พาธแบบเขียนได้ของชนิดค่า
class Counter {
var value: Int = 0
}
let counter = Counter()
let path: ReferenceWritableKeyPath<Counter, Int> = \Counter.value
counter[keyPath: path] = 5
print(counter.value)การอ้างอิงแบบ let แต่อ็อบเจ็กต์เปลี่ยนแปลงได้
สังเกตว่าอินสแตนซ์ของคลาสด้านล่างเป็น let แต่เรายังคงกำหนดค่าคุณสมบัติผ่านคีย์พาธได้ หากเป็นโครงสร้างข้อมูลจะเกิดข้อผิดพลาดขณะคอมไพล์
เป็นเพราะการเปลี่ยนคุณสมบัติของคลาสไม่จำเป็นต้องให้อ้างอิงนั้นเปลี่ยนแปลงได้ เพียงคุณสมบัติเองต้องเปลี่ยนแปลงได้เท่านั้น
class Profile {
var nickname: String = ""
}
let profile = Profile()
let nickPath = \Profile.nickname
profile[keyPath: nickPath] = "Ace"
print(profile.nickname)ลำดับชั้นชนิดของคีย์พาธ
ชนิดคีย์พาธแบบเขียนได้มีลำดับชั้น ReferenceWritableKeyPath เป็นชนิดย่อยของ WritableKeyPath และ WritableKeyPath เป็นชนิดย่อยของ KeyPath ดังนั้นคีย์พาธที่เฉพาะเจาะจงกว่าจึงใช้ได้ทุกที่ที่ต้องการคีย์พาธทั่วไปกว่า
นั่นหมายความว่าคุณสามารถส่ง ReferenceWritableKeyPath ให้ฟังก์ชันที่ต้องการเพียง read ผ่าน KeyPath ได้
class Box { var size: Int = 1 }
func readSize(_ box: Box, _ path: KeyPath<Box, Int>) -> Int {
box[keyPath: path]
}
let writable: ReferenceWritableKeyPath<Box, Int> = \Box.size
print(readSize(Box(), writable))การอัปเดตชนิดค่าที่ซ้อนกัน
คีย์พาธแบบเขียนได้สามารถเชื่อมต่อผ่านโครงสร้างข้อมูลที่ซ้อนกัน การกำหนดค่าคุณสมบัติที่อยู่ลึกลงไปจะเขียนค่าของแต่ละค่าที่ครอบอยู่ตามลำดับกลับขึ้นมา ทั้งหมดนี้ทำได้ด้วยการกำหนดค่าเพียงครั้งเดียว
ที่นี่เราเปลี่ยนค่า city ภายใน address ที่ซ้อนกัน
struct Address { var city: String }
struct Person { var name: String; var address: Address }
var carol = Person(name: "Carol", address: Address(city: "Oslo"))
carol[keyPath: \Person.address.city] = "Bergen"
print(carol.address.city)การใช้การอัปเดตหลายรายการ
เนื่องจากคีย์พาธแบบเขียนได้เป็นค่า คุณจึงจัดเก็บรายการการอัปเดตเป็นคู่คีย์พาธกับค่า แล้วใช้ apply กับคู่เหล่านั้นในลูปได้ นี่คือระบบแพตช์ขนาดเล็ก
ที่นี่เราใช้ apply การเปลี่ยนแปลงสองรายการกับโครงสร้างข้อมูล settings
struct Settings { var volume: Int; var brightness: Int }
var settings = Settings(volume: 5, brightness: 5)
func apply(_ s: inout Settings, _ path: WritableKeyPath<Settings, Int>, _ v: Int) {
s[keyPath: path] = v
}
apply(&settings, \.volume, 8)
apply(&settings, \.brightness, 3)
print(settings)การกำหนดค่าในรูปแบบการเชื่อมต่อ
การใช้งานจริงที่พบได้บ่อยคือสร้างตัวช่วย configure ซึ่งกำหนดคุณสมบัติให้กับอ็อบเจ็กต์ที่เพิ่งสร้าง แล้วคืนค่าอ็อบเจ็กต์นั้นกลับมา ทำให้เขียนโค้ดต่อกันเป็นสายได้ สำหรับคลาส วิธีนี้ใช้ได้กับผลลัพธ์ที่เป็น let
ที่นี่เรากำหนดข้อความของ label ผ่านคีย์พาธอ้างอิงแบบเขียนได้
class Label { var text: String = "" }
func configure<T: AnyObject, V>(_ object: T, _ path: ReferenceWritableKeyPath<T, V>, _ value: V) -> T {
object[keyPath: path] = value
return object
}
let label = configure(Label(), \.text, "Hello")
print(label.text)การเลือกชนิดคีย์พาธที่เหมาะสม
ใช้ KeyPath เมื่อคุณต้องการเพียง read ใช้ WritableKeyPath เพื่อกำหนดคุณสมบัติของชนิดค่าที่เก็บอยู่ใน var และใช้ ReferenceWritableKeyPath เพื่อกำหนดคุณสมบัติของคลาส แม้จะเข้าถึงผ่าน let ก็ตาม
การเลือกชนิดที่เฉพาะเจาะจงที่สุดเท่าที่เหมาะสมช่วยให้ส่วนติดต่อการใช้งานของคุณสื่ออย่างตรงไปตรงมาว่ารองรับการ read หรือการเปลี่ยนแปลงค่า
struct S { var n: Int }
class C { var n: Int = 0 }
let read: KeyPath<S, Int> = \S.n
let writeStruct: WritableKeyPath<S, Int> = \S.n
let writeClass: ReferenceWritableKeyPath<C, Int> = \C.n
print(type(of: read), type(of: writeStruct), type(of: writeClass))ตรวจสอบด่วน: คีย์พาธแบบเขียนได้
ลองนึกดูว่าคีย์พาธชนิดใดที่ช่วยให้คุณกำหนดค่าคุณสมบัติของคลาสได้ แม้อินสแตนซ์จะเป็นค่าคงที่ let
ทบทวน: คีย์พาธแบบเขียนได้และแบบอ้างอิง
คุณได้เรียนรู้วิธีเขียนค่าผ่านคีย์พาธแล้ว:
WritableKeyPathใช้กำหนดค่าคุณสมบัติที่จัดเก็บของชนิดค่า และต้องใช้อินสแตนซ์แบบvarReferenceWritableKeyPathใช้กำหนดค่าคุณสมบัติของคลาส และทำงานได้แม้เข้าถึงผ่านlet- ซับสคริปต์
[keyPath:]จะปรากฏทางด้านซ้ายของการกำหนดค่าเพื่อใช้เขียนค่า - ชนิดเหล่านี้มีลำดับชั้น ดังนั้นคีย์พาธแบบเขียนได้จึงใช้แทนคีย์พาธแบบอ่านอย่างเดียวได้
- ตัวกำหนดค่าแบบทั่วไปที่ใช้
inoutและตัวช่วย configure ล้วนสร้างขึ้นบนแนวคิดเหล่านี้
ถัดไปคุณจะได้พบกับ @dynamicMemberLookup ซึ่งใช้คีย์พาธเพื่อมอบการเข้าถึงข้อมูลแบบไดนามิกด้วยรูปแบบจุด
struct Person { var name: String; var age: Int }
var dave = Person(name: "Dave", age: 27)
dave[keyPath: \Person.age] = 28
print("Updated age: \(dave.age)")คำถามที่พบบ่อย
บทเรียน “KeyPath ที่เขียนได้และอ้างอิงได้” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “KeyPath ที่เขียนได้และอ้างอิงได้” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Swift Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Swift Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “KeyPath ที่เขียนได้และอ้างอิงได้”
อ่านและเขียนผ่านเส้นทางคีย์ คุณปฏิบัติ Swift Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Swift Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Swift Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “KeyPath ที่เขียนได้และอ้างอิงได้” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Swift Academy นี้ได้ไหม
ได้ บทเรียน Swift Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- พื้นฐาน KeyPath
- การใช้ KeyPaths ในคอลเลกชัน
- KeyPath ที่เขียนได้และอ้างอิงได้
- @dynamicMemberLookup