我有一个用于解析json的函数,它工作正常,但不是我重复的事情,我正在寻找一种方法来重构它,以便我可以将我的任何模型对象传递给函数的闭包,它应该仍然以同样的方式行事。
这是我必须传递给有趣的对象列表
下面的函数将Video作为闭包的参数
func fetchFeedForUrlString(urlString: String, completion: @escaping ([Video]) -> ()){
let url = NSURL(string: urlString)!
URLSession.shared.dataTask(with: url as URL) { (data, responseUrl, error) -> Void in
if error != nil{
print("Unable to fetch data\(error)")
return
}
if let wrappedData = data,
let json = try? JSONSerialization.jsonObject(with: wrappedData, options: .allowFragments) as? [String: Any]{
if let results = json?["data"] as? [[String: AnyObject]]{
let videos = results.map({return Video(dictionary: $0)})
DispatchQueue.main.async {
completion(videos)
}
}
}
}.resume()
}
答案 0 :(得分:1)
实际上有点难以告诉你如何重构它,但首先我要说你应该宣布一个JSONDecodable
协议,或者某种协议。通过这种方式,您可以定义描述可以通过JSON初始化的对象的协议。
protocol JSONDecodable {
init?(_ json: [String: Any])
}
使Video
类符合JSONDecodable
协议
class Video: JSONDecodable {
init?(_ json: [String: Any]) {
// your init code here. It can return nil in case the JSON is invalid
}
}
然后您可以使用Swift泛型来创建泛型函数
func fetchFeedForUrlString<T: JSONDecodable>(urlString: String, completion: @escaping ([T]) -> ()){
let url = NSURL(string: urlString)!
URLSession.shared.dataTask(with: url as URL) { (data, responseUrl, error) -> Void in
if error != nil{
print("Unable to fetch data\(error)")
return
}
if let wrappedData = data,
let json = try? JSONSerialization.jsonObject(with: wrappedData, options: .allowFragments) as? [String: Any]{
if let results = json?["data"] as? [[String: AnyObject]]{
let videos = results.flatMap({return T($0)})
DispatchQueue.main.async {
completion(videos)
}
}
}
}.resume()
}
要小心,因为这样你必须声明两个不同的函数来解析一组JSONDecodable
个对象或只有一个。
要使用它,只需写下
即可Instance.fetchFeedForUrlString(...) { (videos as [Video]) in
/// your code here
}
编写(videos as [Video])
,告诉编译器T
参数是Video
类型,否则无法在其他地方推断出类型。
这种实施方式并不是最好的,而且还可以改进。