- Published on
Swiftda Codable
- Authors
- Name
- ShoxruxC
- @iOSdasturchi
Codable protokoli
Codable — Encodable va Decodable ni birlashtirgan protokol. U Swift ob'ektlarni JSON, XML, Property List kabi formatlarga aylantirish (encode) va qaytarish (decode) imkonini beradi. iOS dasturlashda tarmoq so'rovlari (API dan JSON olish), fayl saqlash va ma'lumotlar bazasi bilan ishlashda har kuni kerak.
Asosiy komponentlar: JSONEncoder — Swift ob'ektni JSON ga aylantiradi. JSONDecoder — JSON ni Swift ob'ektga aylantiradi. Struct yoki class Codable ga mos kelsa — barcha property lar avtomatik encode/decode bo'ladi.
Asosiy encode va decode
Quyida oddiy Codable struct yaratish, uni JSON ga aylantirish (encode) va JSON dan qaytarish (decode) ko'rsatilgan.
// ═══════════════════════════════════════
// CODABLE STRUCT
// ═══════════════════════════════════════
struct Foydalanuvchi: Codable {
let id: Int
let ism: String
let email: String
let yosh: Int
}
// ═══════════════════════════════════════
// ENCODE — Swift → JSON
// ═══════════════════════════════════════
let ali = Foydalanuvchi(id: 1, ism: "Ali", email: "ali@mail.com", yosh: 25)
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted // Chiroyli format
let jsonData = try encoder.encode(ali)
let jsonMatn = String(data: jsonData, encoding: .utf8)!
print(jsonMatn)
// {
// "id" : 1,
// "ism" : "Ali",
// "email" : "ali@mail.com",
// "yosh" : 25
// }
// ═══════════════════════════════════════
// DECODE — JSON → Swift
// ═══════════════════════════════════════
let jsonString = """
{
"id": 2,
"ism": "Vali",
"email": "vali@mail.com",
"yosh": 30
}
"""
let data = jsonString.data(using: .utf8)!
let decoder = JSONDecoder()
let vali = try decoder.decode(Foydalanuvchi.self, from: data)
print(vali.ism) // "Vali"
print(vali.email) // "vali@mail.com"
CodingKeys — nom moslash
Ko'p API lar JSON kalitlarni snake_case (masalan, user_id) da yuboradi, lekin Swift da camelCase (userId) ishlatiladi. CodingKeys enum bu nomlarni moslashtiradi. Yoki JSONDecoder ning keyDecodingStrategy ni .convertFromSnakeCase ga o'rnatib, avtomatik konvertatsiya qilish mumkin.
// ═══════════════════════════════════════
// SERVER JSON — snake_case (ko'p API lar shunday)
// ═══════════════════════════════════════
// {
// "user_id": 1,
// "full_name": "Ali Valiyev",
// "email_address": "ali@mail.com",
// "is_active": true
// }
struct Foydalanuvchi: Codable {
let userId: Int // user_id → userId
let fullName: String // full_name → fullName
let emailAddress: String // email_address → emailAddress
let isActive: Bool // is_active → isActive
// JSON kalitlarni Swift property larga moslashtirish
enum CodingKeys: String, CodingKey {
case userId = "user_id"
case fullName = "full_name"
case emailAddress = "email_address"
case isActive = "is_active"
}
}
// YOKI — avtomatik konvertatsiya
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
// Endi CodingKeys yozish shart emas — avtomatik ishlaydi!
Nested JSON — ichma-ich tuzilma
Real API lardan keladigan JSON ko'pincha ichma-ich bo'ladi — ob'ekt ichida ob'ekt, massiv. Har bir ichki tuzilma uchun alohida Codable struct yaratiladi. Swift avtomatik ravishda ularni to'g'ri decode qiladi.
// ═══════════════════════════════════════
// ICHMA-ICH JSON
// ═══════════════════════════════════════
// {
// "id": 1,
// "name": "Ali",
// "address": {
// "city": "Toshkent",
// "street": "Navoiy ko'chasi",
// "zip": "100001"
// },
// "phones": ["998901234567", "998712345678"]
// }
// Har bir ichki ob'ekt — alohida Codable struct
struct Manzil: Codable {
let city: String
let street: String
let zip: String
}
struct Shaxs: Codable {
let id: Int
let name: String
let address: Manzil // Ichki ob'ekt
let phones: [String] // Massiv
}
let json = """
{
"id": 1,
"name": "Ali",
"address": {
"city": "Toshkent",
"street": "Navoiy ko'chasi",
"zip": "100001"
},
"phones": ["998901234567", "998712345678"]
}
""".data(using: .utf8)!
let shaxs = try JSONDecoder().decode(Shaxs.self, from: json)
print(shaxs.address.city) // "Toshkent"
print(shaxs.phones[0]) // "998901234567"
Sana bilan ishlash
JSON da sanalar turli formatlarda keladi: ISO 8601 ("2024-01-15T10:30:00Z"), Unix timestamp (1705312200), yoki custom ("15.01.2024"). JSONDecoder ning dateDecodingStrategy xususiyatini o'rnatib, qaysi formatni ishlatishni aytish kerak.
struct Hodisa: Codable {
let nomi: String
let sana: Date
}
// ISO 8601 format: "2024-01-15T10:30:00Z"
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
// Custom format
let formatter = DateFormatter()
formatter.dateFormat = "dd.MM.yyyy"
decoder.dateDecodingStrategy = .formatted(formatter)
// Endi "15.01.2024" formatini tushunadi
Massiv decode qilish
JSON massivni decode qilish uchun [Struct].self ishlatiladi. Har bir element alohida decode bo'ladi.
// ═══════════════════════════════════════
// JSON MASSIV
// ═══════════════════════════════════════
let jsonMassiv = """
[
{"id": 1, "ism": "Ali", "email": "ali@mail.com", "yosh": 25},
{"id": 2, "ism": "Vali", "email": "vali@mail.com", "yosh": 30},
{"id": 3, "ism": "Gani", "email": "gani@mail.com", "yosh": 22}
]
""".data(using: .utf8)!
// [Foydalanuvchi].self — massiv sifatida decode
let foydalanuvchilar = try JSONDecoder().decode(
[Foydalanuvchi].self,
from: jsonMassiv
)
print(foydalanuvchilar.count) // 3
Optional va default qiymatlar
Optional property — JSON da topilmasa nil bo'ladi (crash emas). Lekin Codable da default qiymat (var miqdor: Int = 1) ishlamaydi — buning uchun init(from:) ni o'zingiz yozishingiz va decodeIfPresent bilan default qiymat berishingiz kerak.
struct Mahsulot: Codable {
let id: Int
let nomi: String
let tavsif: String? // JSON da bo'lmasa nil
let narx: Double
let rasm: String? // JSON da bo'lmasa nil
var miqdor: Int = 1 // Lekin Codable da default ishlamaydi!
}
// Default qiymat uchun — init(from:) yozish kerak
struct MahsulotYaxshi: Codable {
let id: Int
let nomi: String
let tavsif: String?
let narx: Double
var miqdor: Int
enum CodingKeys: String, CodingKey {
case id, nomi, tavsif, narx, miqdor
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(Int.self, forKey: .id)
nomi = try container.decode(String.self, forKey: .nomi)
tavsif = try container.decodeIfPresent(String.self, forKey: .tavsif)
narx = try container.decode(Double.self, forKey: .narx)
// Default qiymat — JSON da bo'lmasa 1
miqdor = try container.decodeIfPresent(Int.self, forKey: .miqdor) ?? 1
}
}
🎯 Topshiriq
Quyidagi JSON ni decode qiling:
{"user": {"name": "Ali", "age": 25}, "posts": [{"title": "Salom", "likes": 10}]}
Uchta struct yarating: APIJavob, Foydalanuvchi, Post. Decode qilib, user.name va birinchi post.title ni chiqaring. Encode qilib JSON matnga aylantiring.