如何从 SwiftyJSON 创建对象
How to create objects from SwiftyJSON
我有一个代码,可以解析 JSON 的问题列表,我可以得到每个 属性。如何遍历整个文件并为每个问题创建一个对象?
class ViewController: UIViewController {
var hoge: JSON?
override func viewDidLoad() {
super.viewDidLoad()
let number = arc4random_uniform(1000)
let url = NSURL(string: "http://www.wirehead.ru/try-en.json?\(number)")
var request = NSURLRequest(URL: url!)
var data = NSURLConnection.sendSynchronousRequest(request, returningResponse: nil, error: nil)
if data != nil {
hoge = JSON(data: data!)
let level = hoge!["pack1"][0]["level"].intValue
let questionText = hoge!["pack1"][0]["questionText"].stringValue
let answer1 = hoge!["pack1"][0]["answer1"].stringValue
let answer2 = hoge!["pack1"][0]["answer2"].stringValue
let answer3 = hoge!["pack1"][0]["answer3"].stringValue
let answer4 = hoge!["pack1"][0]["answer4"].stringValue
let correctAnswer = hoge!["pack1"][0]["correctAnswer"].stringValue
let haveAnswered = hoge!["pack1"][0]["haveAnswered"].boolValue
}
}
}
我想在下面创建哪些对象的问题模型
class Question {
var level : Int?
var questionText : String?
var answer1 : String?
var answer2 : String?
var answer3 : String?
var answer4 : String?
var correctAnswer : String?
var haveAnswered : Bool = false
init(level: Int, questionText:String, answer1:String, answer2:String, answer3:String, answer4:String, correctAnswer: String, haveAnswered:Bool) {
self.level = level
self.questionText = questionText
self.answer1 = answer1
self.answer2 = answer2
self.answer3 = answer3
self.answer4 = answer4
self.correctAnswer = correctAnswer
self.haveAnswered = false
}
}
这就是我处理问题的方式。
第 1 步
由于 Question
中的 init
确实收到了 non optional
对象,我觉得问题的属性也应该是非可选的。我还将属性从 var
转换为 let
(如果我错了请告诉我)。
第 2 步
这是重构后的 Question
class。如您所见,我添加了一个 class 方法 build
,它接收一个 JSON
(一个 SwiftyJSON
)和一个 returns 一个 Question
(如果 json 包含正确的数据),否则为零。
Right now I cannot do this with a failable initializer
.
extension String {
func toBool() -> Bool? {
switch self.lowercaseString {
case "true", "1", "yes" : return true
case "false", "0", "no" : return false
default: return nil
}
}
}
class Question {
let level: Int
let questionText: String
let answer1: String
let answer2: String
let answer3: String
let answer4: String
let correctAnswer: String
let haveAnswered: Bool
init(level: Int, questionText:String, answer1:String, answer2:String, answer3:String, answer4:String, correctAnswer: String, haveAnswered:Bool) {
self.level = level
self.questionText = questionText
self.answer1 = answer1
self.answer2 = answer2
self.answer3 = answer3
self.answer4 = answer4
self.correctAnswer = correctAnswer
self.haveAnswered = false
}
class func build(json:JSON) -> Question? {
if let
level = json["level"].string?.toInt(),
questionText = json["questionText"].string,
answer1 = json["answer1"].string,
answer2 = json["answer2"].string,
answer3 = json["answer3"].string,
answer4 = json["answer4"].string,
correctAnswer = json["correctAnswer"].string,
haveAnswered = json["haveAnswered"].string?.toBool() {
return Question(
level: level,
questionText: questionText,
answer1: answer1,
answer2: answer2,
answer3: answer3,
answer4: answer4,
correctAnswer: correctAnswer,
haveAnswered: haveAnswered)
} else {
debugPrintln("bad json \(json)")
return nil
}
}
}
步骤 3
现在让我们看看viewDidLoad
。
func viewDidLoad() {
super.viewDidLoad()
let number = arc4random_uniform(1000)
if let
url = NSURL(string: "http://www.wirehead.ru/try-en.json?\(number)"),
data = NSURLConnection.sendSynchronousRequest(NSURLRequest(URL: url), returningResponse: nil, error: nil) {
// line #a
let rootJSON = JSON(data: data)
// line #b
if let questions = (rootJSON["pack1"].array?.map { return Question.build([=11=]) }) {
// now you have an array of optional questions [Question?]...
}
}
}
在第 #a 行,我在 rootJSON
中放入了从连接接收到的全部数据(转换为 JSON
)。
第 #b 行发生了什么?
好吧,我尝试访问位于 "pack1"
内的数组。
rootJSON["pack1"].array?
如果数组存在我运行映射方法。这将提取数组的每个单元格,我将能够在闭包内使用 [=28=]
参数名称引用它。
在闭包中,我使用这个 json 块(应该代表一个问题)来构建一个 Question
实例。
结果将是 Question?
的数组。如果某些子数据无效,则可能存在不良值。如果你愿意,我可以告诉你如何从这个数组
中删除 nil
值
我无法用真实数据尝试代码,希望这对您有所帮助。
for (item, content) in hoge {
let level = content["level"].intValue
}
应该可行
第 1 步。我们将创建一个协议,其中包含一个构造方法和模型 class
protocol JSONable {
init?(parameter: JSON)
}
class Style: JSONable {
let ID :String!
let name :String!
required init(parameter: JSON) {
ID = parameter["id"].stringValue
name = parameter["name"].stringValue
}
/* JSON response format
{
"status": true,
"message": "",
"data": [
{
"id": 1,
"name": "Style 1"
},
{
"id": 2,
"name": "Style 2"
},
{
"id": 3,
"name": "Style 3"
}
]
}
*/
}
第 2 步。我们将创建 JSON 的扩展,它将 JSON 转换为模型 class 类型对象
extension JSON {
func to<T>(type: T?) -> Any? {
if let baseObj = type as? JSONable.Type {
if self.type == .array {
var arrObject: [Any] = []
for obj in self.arrayValue {
let object = baseObj.init(parameter: obj)
arrObject.append(object!)
}
return arrObject
} else {
let object = baseObj.init(parameter: self)
return object!
}
}
return nil
}
}
第 3 步。将代码与 Alamofire 或其他代码一起使用。
Alamofire.request(.GET, url).validate().responseJSON { response in
switch response.result {
case .success(let value):
let json = JSON(value)
var styles: [Style] = []
if let styleArr = json["data"].to(type: Style.self) {
styles = styleArr as! [Style]
}
print("styles: \(styles)")
case .failure(let error):
print(error)
}
}
希望对您有所帮助。
有关这方面的更多信息,请参阅此 link。
https://github.com/SwiftyJSON/SwiftyJSON/issues/714
您可以使用专门为此目的设计的 SwiftyJSONModel。因此,在您的情况下,模型将是这样的:
class Question: JSONObjectInitializable {
enum PropertyKey: String {
case level, questionText
case answer1, answer2, answer3, answer4
case correctAnswer, haveAnswered
}
var level : Int?
var questionText : String?
var answer1 : String?
var answer2 : String?
var answer3 : String?
var answer4 : String?
var correctAnswer : String?
var haveAnswered : Bool = false
required init(object: JSONObject<PropertyKey>) throws {
level = object.value(for: .level)
questionText = object.value(for: .questionText)
answer1 = object.value(for: .answer1)
answer2 = object.value(for: .answer2)
answer3 = object.value(for: .answer3)
answer4 = object.value(for: .answer4)
correctAnswer = object.value(for: .correctAnswer)
haveAnswered = object.value(for: .haveAnswered) ?? false
}
}
然后这样做:
let rootJSON = JSON(data: data)
let questions = rootJSON.arrayValue.flatMap { try? Question(json: [=11=]) }
该框架为您提供了几个不错的功能:
- 所有的键都存储在单独的枚举中
PropertyKey
- 没有样板,如
stringValue
、intValue
等
- 如果
JSON
无效,框架将给出一个详细的错误,您将立即看到到底出了什么问题
我有一个代码,可以解析 JSON 的问题列表,我可以得到每个 属性。如何遍历整个文件并为每个问题创建一个对象?
class ViewController: UIViewController {
var hoge: JSON?
override func viewDidLoad() {
super.viewDidLoad()
let number = arc4random_uniform(1000)
let url = NSURL(string: "http://www.wirehead.ru/try-en.json?\(number)")
var request = NSURLRequest(URL: url!)
var data = NSURLConnection.sendSynchronousRequest(request, returningResponse: nil, error: nil)
if data != nil {
hoge = JSON(data: data!)
let level = hoge!["pack1"][0]["level"].intValue
let questionText = hoge!["pack1"][0]["questionText"].stringValue
let answer1 = hoge!["pack1"][0]["answer1"].stringValue
let answer2 = hoge!["pack1"][0]["answer2"].stringValue
let answer3 = hoge!["pack1"][0]["answer3"].stringValue
let answer4 = hoge!["pack1"][0]["answer4"].stringValue
let correctAnswer = hoge!["pack1"][0]["correctAnswer"].stringValue
let haveAnswered = hoge!["pack1"][0]["haveAnswered"].boolValue
}
}
}
我想在下面创建哪些对象的问题模型
class Question {
var level : Int?
var questionText : String?
var answer1 : String?
var answer2 : String?
var answer3 : String?
var answer4 : String?
var correctAnswer : String?
var haveAnswered : Bool = false
init(level: Int, questionText:String, answer1:String, answer2:String, answer3:String, answer4:String, correctAnswer: String, haveAnswered:Bool) {
self.level = level
self.questionText = questionText
self.answer1 = answer1
self.answer2 = answer2
self.answer3 = answer3
self.answer4 = answer4
self.correctAnswer = correctAnswer
self.haveAnswered = false
}
}
这就是我处理问题的方式。
第 1 步
由于 Question
中的 init
确实收到了 non optional
对象,我觉得问题的属性也应该是非可选的。我还将属性从 var
转换为 let
(如果我错了请告诉我)。
第 2 步
这是重构后的 Question
class。如您所见,我添加了一个 class 方法 build
,它接收一个 JSON
(一个 SwiftyJSON
)和一个 returns 一个 Question
(如果 json 包含正确的数据),否则为零。
Right now I cannot do this with a
failable initializer
.
extension String {
func toBool() -> Bool? {
switch self.lowercaseString {
case "true", "1", "yes" : return true
case "false", "0", "no" : return false
default: return nil
}
}
}
class Question {
let level: Int
let questionText: String
let answer1: String
let answer2: String
let answer3: String
let answer4: String
let correctAnswer: String
let haveAnswered: Bool
init(level: Int, questionText:String, answer1:String, answer2:String, answer3:String, answer4:String, correctAnswer: String, haveAnswered:Bool) {
self.level = level
self.questionText = questionText
self.answer1 = answer1
self.answer2 = answer2
self.answer3 = answer3
self.answer4 = answer4
self.correctAnswer = correctAnswer
self.haveAnswered = false
}
class func build(json:JSON) -> Question? {
if let
level = json["level"].string?.toInt(),
questionText = json["questionText"].string,
answer1 = json["answer1"].string,
answer2 = json["answer2"].string,
answer3 = json["answer3"].string,
answer4 = json["answer4"].string,
correctAnswer = json["correctAnswer"].string,
haveAnswered = json["haveAnswered"].string?.toBool() {
return Question(
level: level,
questionText: questionText,
answer1: answer1,
answer2: answer2,
answer3: answer3,
answer4: answer4,
correctAnswer: correctAnswer,
haveAnswered: haveAnswered)
} else {
debugPrintln("bad json \(json)")
return nil
}
}
}
步骤 3
现在让我们看看viewDidLoad
。
func viewDidLoad() {
super.viewDidLoad()
let number = arc4random_uniform(1000)
if let
url = NSURL(string: "http://www.wirehead.ru/try-en.json?\(number)"),
data = NSURLConnection.sendSynchronousRequest(NSURLRequest(URL: url), returningResponse: nil, error: nil) {
// line #a
let rootJSON = JSON(data: data)
// line #b
if let questions = (rootJSON["pack1"].array?.map { return Question.build([=11=]) }) {
// now you have an array of optional questions [Question?]...
}
}
}
在第 #a 行,我在 rootJSON
中放入了从连接接收到的全部数据(转换为 JSON
)。
第 #b 行发生了什么?
好吧,我尝试访问位于 "pack1"
内的数组。
rootJSON["pack1"].array?
如果数组存在我运行映射方法。这将提取数组的每个单元格,我将能够在闭包内使用 [=28=]
参数名称引用它。
在闭包中,我使用这个 json 块(应该代表一个问题)来构建一个 Question
实例。
结果将是 Question?
的数组。如果某些子数据无效,则可能存在不良值。如果你愿意,我可以告诉你如何从这个数组
nil
值
我无法用真实数据尝试代码,希望这对您有所帮助。
for (item, content) in hoge {
let level = content["level"].intValue
}
应该可行
第 1 步。我们将创建一个协议,其中包含一个构造方法和模型 class
protocol JSONable {
init?(parameter: JSON)
}
class Style: JSONable {
let ID :String!
let name :String!
required init(parameter: JSON) {
ID = parameter["id"].stringValue
name = parameter["name"].stringValue
}
/* JSON response format
{
"status": true,
"message": "",
"data": [
{
"id": 1,
"name": "Style 1"
},
{
"id": 2,
"name": "Style 2"
},
{
"id": 3,
"name": "Style 3"
}
]
}
*/
}
第 2 步。我们将创建 JSON 的扩展,它将 JSON 转换为模型 class 类型对象
extension JSON {
func to<T>(type: T?) -> Any? {
if let baseObj = type as? JSONable.Type {
if self.type == .array {
var arrObject: [Any] = []
for obj in self.arrayValue {
let object = baseObj.init(parameter: obj)
arrObject.append(object!)
}
return arrObject
} else {
let object = baseObj.init(parameter: self)
return object!
}
}
return nil
}
}
第 3 步。将代码与 Alamofire 或其他代码一起使用。
Alamofire.request(.GET, url).validate().responseJSON { response in
switch response.result {
case .success(let value):
let json = JSON(value)
var styles: [Style] = []
if let styleArr = json["data"].to(type: Style.self) {
styles = styleArr as! [Style]
}
print("styles: \(styles)")
case .failure(let error):
print(error)
}
}
希望对您有所帮助。
有关这方面的更多信息,请参阅此 link。
https://github.com/SwiftyJSON/SwiftyJSON/issues/714
您可以使用专门为此目的设计的 SwiftyJSONModel。因此,在您的情况下,模型将是这样的:
class Question: JSONObjectInitializable {
enum PropertyKey: String {
case level, questionText
case answer1, answer2, answer3, answer4
case correctAnswer, haveAnswered
}
var level : Int?
var questionText : String?
var answer1 : String?
var answer2 : String?
var answer3 : String?
var answer4 : String?
var correctAnswer : String?
var haveAnswered : Bool = false
required init(object: JSONObject<PropertyKey>) throws {
level = object.value(for: .level)
questionText = object.value(for: .questionText)
answer1 = object.value(for: .answer1)
answer2 = object.value(for: .answer2)
answer3 = object.value(for: .answer3)
answer4 = object.value(for: .answer4)
correctAnswer = object.value(for: .correctAnswer)
haveAnswered = object.value(for: .haveAnswered) ?? false
}
}
然后这样做:
let rootJSON = JSON(data: data)
let questions = rootJSON.arrayValue.flatMap { try? Question(json: [=11=]) }
该框架为您提供了几个不错的功能:
- 所有的键都存储在单独的枚举中
PropertyKey
- 没有样板,如
stringValue
、intValue
等 - 如果
JSON
无效,框架将给出一个详细的错误,您将立即看到到底出了什么问题