0Pricing
Swift Academy · บทเรียน

การเข้ารหัสด้วยตนเองด้วย encode(to:) และ init(from:)

ควบคุมตรรกะการแปลงข้อมูลเป็นรูปแบบจัดเก็บได้อย่างเต็มที่

การเข้ารหัสด้วยตนเองด้วย encode(to:) และ init(from:) เป็นบทเรียน Swift Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Swift Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Swift Academy มีบทเรียนทั้งหมด 4 บทเรียน

เมื่อการสร้างโค้ดอัตโนมัติไม่เพียงพอ

บางครั้งโครงสร้าง JSON ไม่ตรงกับคุณสมบัติของคุณ คุณอาจต้องแปลงค่าที่คำนวณ กำหนดค่าทดแทนเริ่มต้น หรือทำโครงสร้างที่ซ้อนกันให้แบนราบ ในกรณีนั้น คุณต้องเขียน encode(to:) และ init(from:) ด้วยตนเอง

import Foundation

struct Temperature: Codable {
    var celsius: Double
}

print("Manual coding gives full control")

ประกาศ CodingKeys ก่อน

การเขียนโค้ดด้วยตนเองเริ่มจาก enum CodingKeys คอนเทนเนอร์แบบใช้คีย์จะใช้คีย์เหล่านี้เพื่ออ่านและเขียนค่า

import Foundation

struct User {
    var name: String
    var age: Int
    enum CodingKeys: String, CodingKey {
        case name
        case age
    }
}

print(User.CodingKeys.name.stringValue)

การใช้งาน init(from:)

init(from decoder:) จะรับคอนเทนเนอร์แบบใช้คีย์ด้วย container(keyedBy:) จากนั้นจึงถอดรหัสคุณสมบัติแต่ละรายการด้วยคีย์ของรายการนั้น

import Foundation

struct User: Decodable {
    var name: String
    var age: Int
    enum CodingKeys: String, CodingKey { case name, age }
    init(from decoder: Decoder) throws {
        let c = try decoder.container(keyedBy: CodingKeys.self)
        name = try c.decode(String.self, forKey: .name)
        age = try c.decode(Int.self, forKey: .age)
    }
}

let u = try JSONDecoder().decode(User.self, from: "{\"name\":\"Ada\",\"age\":36}".data(using: .utf8)!)
print(u.name, u.age)

การใช้งาน encode(to:)

encode(to encoder:) จะรับคอนเทนเนอร์แบบใช้คีย์ที่แก้ไขได้ด้วย container(keyedBy:) แล้วเขียนคุณสมบัติแต่ละรายการด้วย encode(_:forKey:)

import Foundation

struct User: Encodable {
    var name: String
    var age: Int
    enum CodingKeys: String, CodingKey { case name, age }
    func encode(to encoder: Encoder) throws {
        var c = encoder.container(keyedBy: CodingKeys.self)
        try c.encode(name, forKey: .name)
        try c.encode(age, forKey: .age)
    }
}

let data = try JSONEncoder().encode(User(name: "Ada", age: 36))
print(String(data: data, encoding: .utf8)!)

การทำ Codable ด้วยตนเองทั้งหมด

การใช้งานทั้งสองเมธอดจะทำให้ชนิดข้อมูลรองรับ Codable ได้อย่างสมบูรณ์ พร้อมตรรกะที่กำหนดเองทั้งฝั่งอ่านและฝั่งเขียน

import Foundation

struct Point: Codable {
    var x: Int
    var y: Int
    enum CodingKeys: String, CodingKey { case x, y }
    init(x: Int, y: Int) { self.x = x; self.y = y }
    init(from d: Decoder) throws {
        let c = try d.container(keyedBy: CodingKeys.self)
        x = try c.decode(Int.self, forKey: .x)
        y = try c.decode(Int.self, forKey: .y)
    }
    func encode(to e: Encoder) throws {
        var c = e.container(keyedBy: CodingKeys.self)
        try c.encode(x, forKey: .x)
        try c.encode(y, forKey: .y)
    }
}

let back = try JSONDecoder().decode(Point.self, from: try JSONEncoder().encode(Point(x: 1, y: 2)))
print(back.x, back.y)

การกำหนดค่าเริ่มต้น

ใช้ decodeIfPresent ร่วมกับตัวดำเนินการรวมค่า nil เพื่อกำหนดค่าเริ่มต้นเมื่อไม่มีคีย์ แทนที่จะทำให้เกิดข้อผิดพลาด

import Foundation

struct Settings: Decodable {
    var theme: String
    enum CodingKeys: String, CodingKey { case theme }
    init(from decoder: Decoder) throws {
        let c = try decoder.container(keyedBy: CodingKeys.self)
        theme = try c.decodeIfPresent(String.self, forKey: .theme) ?? "light"
    }
}

let s = try JSONDecoder().decode(Settings.self, from: "{}".data(using: .utf8)!)
print(s.theme)

การแปลงค่า

การถอดรหัสด้วยตนเองช่วยให้คุณแปลง JSON ดิบเป็นรูปแบบที่มีความหมายมากขึ้นได้ ในตัวอย่างนี้ ค่าที่ป้อนเป็นฟาเรนไฮต์จะถูกจัดเก็บเป็นเซลเซียส

import Foundation

struct Reading: Decodable {
    var celsius: Double
    enum CodingKeys: String, CodingKey { case fahrenheit }
    init(from decoder: Decoder) throws {
        let c = try decoder.container(keyedBy: CodingKeys.self)
        let f = try c.decode(Double.self, forKey: .fahrenheit)
        celsius = (f - 32) * 5 / 9
    }
}

let r = try JSONDecoder().decode(Reading.self, from: "{\"fahrenheit\":212}".data(using: .utf8)!)
print(r.celsius)

การทำ JSON ที่ซ้อนกันให้แบนราบ

คุณสามารถอ่านคอนเทนเนอร์ที่ซ้อนกันด้วย nestedContainer(keyedBy:forKey:) แล้วนำค่าของคอนเทนเนอร์นั้นขึ้นมาไว้ในโครงสร้าง Swift แบบแบนราบได้

import Foundation

struct Profile: Decodable {
    var city: String
    enum Keys: String, CodingKey { case address }
    enum AddressKeys: String, CodingKey { case city }
    init(from decoder: Decoder) throws {
        let c = try decoder.container(keyedBy: Keys.self)
        let a = try c.nestedContainer(keyedBy: AddressKeys.self, forKey: .address)
        city = try a.decode(String.self, forKey: .city)
    }
}

let json = "{\"address\":{\"city\":\"Rome\"}}"
let p = try JSONDecoder().decode(Profile.self, from: json.data(using: .utf8)!)
print(p.city)

การเข้ารหัสลงในคอนเทนเนอร์ที่ซ้อนกัน

การเข้ารหัสสามารถทำย้อนกลับได้เช่นกัน โดยเขียนโครงสร้างแบบแบนราบออกมาเป็นออบเจ็กต์ JSON ที่ซ้อนกันด้วย nestedContainer(keyedBy:forKey:)

import Foundation

struct Profile: Encodable {
    var city: String
    enum Keys: String, CodingKey { case address }
    enum AddressKeys: String, CodingKey { case city }
    func encode(to encoder: Encoder) throws {
        var c = encoder.container(keyedBy: Keys.self)
        var a = c.nestedContainer(keyedBy: AddressKeys.self, forKey: .address)
        try a.encode(city, forKey: .city)
    }
}

let data = try JSONEncoder().encode(Profile(city: "Rome"))
print(String(data: data, encoding: .utf8)!)

การตรวจสอบระหว่างการถอดรหัส

เนื่องจาก init(from:) เป็นเพียงตัวเริ่มต้น คุณจึงสามารถตรวจสอบค่าและส่งข้อผิดพลาดที่กำหนดเองได้เมื่อค่าอยู่นอกช่วงที่กำหนด

import Foundation

struct Score: Decodable {
    var value: Int
    enum CodingKeys: String, CodingKey { case value }
    init(from decoder: Decoder) throws {
        let c = try decoder.container(keyedBy: CodingKeys.self)
        let v = try c.decode(Int.self, forKey: .value)
        guard (0...100).contains(v) else {
            throw DecodingError.dataCorruptedError(forKey: .value, in: c, debugDescription: "out of range")
        }
        value = v
    }
}

let s = try JSONDecoder().decode(Score.self, from: "{\"value\":80}".data(using: .utf8)!)
print(s.value)

การผสมการเขียนด้วยตนเองและการสร้างอัตโนมัติ

ชนิดข้อมูลสามารถเขียนเพียงเมธอดเดียวด้วยตนเอง แล้วให้คอมไพเลอร์สร้างอีกเมธอดหนึ่งโดยอัตโนมัติได้ ตัวอย่างเช่น เขียน init(from:) เอง แต่ใช้การเข้ารหัสที่สร้างขึ้นโดยอัตโนมัติ

import Foundation

struct Flag: Codable {
    var on: Bool
    enum CodingKeys: String, CodingKey { case on }
    init(from decoder: Decoder) throws {
        let c = try decoder.container(keyedBy: CodingKeys.self)
        on = (try? c.decode(Bool.self, forKey: .on)) ?? false
    }
    init(on: Bool) { self.on = on }
}

let data = try JSONEncoder().encode(Flag(on: true))
print(String(data: data, encoding: .utf8)!)

ตรวจความเข้าใจอย่างรวดเร็ว: การเขียนโค้ดด้วยตนเอง

ทดสอบความเข้าใจของคุณเกี่ยวกับเมธอด Codable ที่เขียนด้วยตนเอง

ทบทวน: encode(to:) และ init(from:) ด้วยตนเอง

คุณได้เรียนรู้การควบคุมการเขียนโค้ดอย่างสมบูรณ์แล้ว:

  • ประกาศ CodingKeys จากนั้นใช้งาน init(from:) และ encode(to:)
  • ใช้ container(keyedBy:) และ encode/decode(_:forKey:)
  • decodeIfPresent ร่วมกับ ?? เพื่อกำหนดค่าเริ่มต้น ส่วน nestedContainer ใช้ทำ JSON ให้แบนราบหรือซ้อนกัน
  • คุณสามารถตรวจสอบ แปลงค่า และผสมเมธอดที่เขียนด้วยตนเองเข้ากับเมธอดที่สร้างขึ้นโดยอัตโนมัติได้

คำถามที่พบบ่อย

บทเรียน “การเข้ารหัสด้วยตนเองด้วย encode(to:) และ init(from:)” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การเข้ารหัสด้วยตนเองด้วย encode(to:) และ init(from:)” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Swift Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Swift Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การเข้ารหัสด้วยตนเองด้วย encode(to:) และ init(from:)”

ควบคุมตรรกะการแปลงข้อมูลเป็นรูปแบบจัดเก็บได้อย่างเต็มที่ คุณปฏิบัติ Swift Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Swift Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Swift Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน

บทเรียน “การเข้ารหัสด้วยตนเองด้วย encode(to:) และ init(from:)” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Swift Academy นี้ได้ไหม

ได้ บทเรียน Swift Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. CodingKeys สำหรับการเปลี่ยนชื่อ
  2. กลยุทธ์การถอดรหัสคีย์และวันที่
  3. การเข้ารหัสด้วยตนเองด้วย encode(to:) และ init(from:)
  4. การถอดรหัส JSON ต่างชนิด
← กลับไปที่ Swift Academy