iOS 开发中 JSON 传递 Boolean 类型值的完整指南
在 iOS 开发中,JSON 作为跨数据交换的轻量级格式,经常用于客户端与服务器之间的通信,Boolean 类型(true/false)是常见的数据类型,但开发者常会遇到“传过去的值到服务端变成 true/false 字符串”“本地解析时无法正确识别 Boolean”等问题,本文将详细介绍 iOS 中 JSON 传递 Boolean 类型的正确方法,包括编码、解析、常见问题及解决方案,帮助开发者避坑。
iOS 中 JSON 与 Boolean 的基础关系
JSON 本身支持 Boolean 类型,其原生值为 true 或 false(全小写,无引号),但在 iOS 开发中,由于 Swift 和 Objective-C 的类型系统与 JSON 的差异,Boolean 的传递需要经历“对象转 JSON”(编码)和“JSON 转对象”(解码)两个过程,这两个过程的正确实现是关键。
- 编码(Serialization):将 Swift 的
Bool类型转换为 JSON 的true/false。 - 解码(Deserialization):将 JSON 的
true/false解析为 Swift 的Bool类型。
使用 Codable 协议正确传递 Boolean(Swift 推荐方式)
Swift 4 引入的 Codable 协议是处理 JSON 序列化的现代标准方式,通过定义符合 Codable 的结构体/类,可以自动完成编码和解码,避免手动处理字典的繁琐和错误。
定义符合 Codable 的模型
假设我们要传递一个包含 Boolean 字段(如 isCompleted)的用户数据,首先定义模型:
import Foundation
struct User: Codable {
let id: Int
let name: String
let isCompleted: Bool // Boolean 字段
}
编码:将 Bool 转为 JSON
使用 JSONEncoder 将 User 对象转为 JSON 数据(Data 类型),再通过 String 转换可直观查看结果:
let user = User(id: 1, name: "Alice", isCompleted: true)
do {
let jsonData = try JSONEncoder().encode(user)
let jsonString = String(data: jsonData, encoding: .utf8)!
print("JSON 字符串: \(jsonString)")
} catch {
print("编码失败: \(error)")
}
输出结果:
{"id":1,"name":"Alice","isCompleted":true}
可以看到,isCompleted: true 正确转为了 JSON 原生的 Boolean 值(无引号)。
解码:将 JSON 的 true/false 解析为 Bool
使用 JSONDecoder 将 JSON 数据解析回 User 对象:
let jsonString = """
{"id":1,"name":"Bob","isCompleted":false}
"""
do {
let jsonData = jsonString.data(using: .utf8)!
let user = try JSONDecoder().decode(User.self, from: jsonData)
print("解析后的用户: \(user), 是否完成: \(user.isCompleted)")
} catch {
print("解码失败: \(error)")
}
输出结果:
解析后的用户: User(id: 1, name: "Bob", isCompleted: false), 是否完成: false
isCompleted 成功从 JSON 的 false 解析为 Swift 的 Bool 类型。
常见问题:JSON 中的 Boolean 被误解析为 String
如果服务端返回的 JSON 中,Boolean 值被错误地用引号包裹(如 "isCompleted": "true"),直接解码会失败,此时需要自定义解码逻辑,处理这种“伪 Boolean”字符串。
解决方案:自定义 CodingKeys 和 decodeIfPresent
假设 JSON 中可能存在 "true"/"false" 字符串或 true/false 原生值,扩展 User 模型,添加自定义解码方法:
struct User: Codable {
let id: Int
let name: String
let isCompleted: Bool
// 自定义解码逻辑
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(Int.self, forKey: .id)
name = try container.decode(String.self, forKey: .name)
// 尝试解码 Bool(原生 JSON 值)
if let isBool = try? container.decode(Bool.self, forKey: .isCompleted) {
isCompleted = isBool
}
// 尝试解码 String(引号包裹的值)
else if let isString = try? container.decode(String.self, forKey: .isCompleted),
let isBool = Bool(isString) {
isCompleted = isBool
} else {
throw DecodingError.dataCorruptedError(forKey: .isCompleted, in: container, debugDescription: "无法解析 isCompleted,期望 Boolean 或 Boolean 字符串")
}
}
}
测试用例:
let problematicJson = """
{"id":2,"name":"Charlie","isCompleted":"true"}
"""
do {
let jsonData = problematicJson.data(using: .utf8)!
let user = try JSONDecoder().decode(User.self, from: jsonData)
print("解析成功: \(user.isCompleted)") // 输出: true
} catch {
print("错误: \(error)")
}
此时即使 JSON 中 "isCompleted" 是字符串 "true",也能正确解析为 Bool 类型。
Objective-C 中的 JSON Boolean 传递
对于仍在使用 Objective-C 的项目,可以通过 NSJSONSerialization 处理 JSON,但需注意类型转换。
编码:将 BOOL 转为 JSON
Objective-C 的 BOOL 类型本质是 NSInteger(0 为 NO,非 0 为 YES),但 JSON 要求 true/false,需手动转换为 NSNumber:
NSDictionary *user = @{
@"id": @1,
@"name": @"Alice",
@"isCompleted": @YES // 必须用 @YES/@NO 或 @(YES)/@(NO) 包装
};
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:user options:0 error:nil];
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSLog(@"JSON 字符串: %@", jsonString);
输出结果:
{"id":1,"name":"Alice","isCompleted":true}
解码:从 JSON 中提取 BOOL
从 JSON 字典中解析 isCompleted 时,需确保值是 NSNumber 并转换为 BOOL:
NSString *jsonString = @"{\"id\":1,\"name\":\"Bob\",\"isCompleted\":false}";
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil];
// 从字典中获取 isCompleted,确保是 NSNumber
NSNumber *isCompletedNumber = jsonDict[@"isCompleted"];
if ([isCompletedNumber isKindOfClass:[NSNumber class]]) {
BOOL isCompleted = [isCompletedNumber boolValue];
NSLog(@"是否完成: %d", isCompleted); // 输出: 0 (NO)
} else {
NSLog(@"isCompleted 不是有效数值");
}
注意:JSON 中 "isCompleted" 是字符串(如 "true"),需先转为 NSString 再通过 [str boolValue] 解析:
if ([isCompletedNumber isKindOfClass:[NSString class]]) {
NSString *isCompletedStr = (NSString *)isCompletedNumber;
BOOL isCompleted = [isCompletedStr boolValue]; // "true" -> YES, "false" -> NO
NSLog(@"是否完成: %d", isCompleted);
}
常见问题与解决方案
问题:服务端返回的 Boolean 是字符串(如 "true"),本地解析失败
原因:服务端未遵循 JSON 规范,将 Boolean 值用引号包裹为字符串。
解决:
- Swift:如前所述,通过自定义
Codable解码逻辑,兼容字符串和原生 Boolean。 - Objective-C:判断值类型,如果是字符串则调用
[str boolValue]解析。
问题:编码后 JSON 中 Boolean 变成 1/0 或 "1"/"0"
原因:
- Swift 中未使用
JSONEncoder的outputFormatting选项,或误将Bool转为Int。 - Objective-C 中直接使用
@1/@0而非@YES/@NO。
解决:
- Swift:确保使用
JSONEncoder.encode(),且Bool字段未手动转为其他类型。 - Objective-C:使用
@YES/



还没有评论,来说两句吧...