我正在使用名为Gloss的库来帮助解析JSON数据。结果我创建了Glossy:
类型的结构struct LoyaltyCard: Glossy {
let id: Int
init?(json: JSON) {
guard let __id: Int = "id" <~~ json
else { return nil }
}
我有许多不同的Glossy结构,并希望将它们与字符串一起传递给函数但是我一直收到错误:“无法使用类型'的参数列表调用'getMemberInfo'(String,memberData:LoyaltyCard.Type) '“,这是我的函数的缩写版本:
func getMemberInfo<T: Glossy> (memberDataRequest: String, memberData:T) {
let urlAccess = "\(baseURL)/api/\(memberDataRequest)"
///////code////////////
let data = object as! NSData
let jsonInfo: AnyObject? = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.init(rawValue: 0))
let jsonArray = jsonInfo as! NSArray
if let dict = jsonArray[0] as? JSON //This means as type Gloss
{
let loyaltyID= LoyaltyCard(json: dict)
print(loyaltyID?.id)
}
}
如何使这项功能发挥作用?
答案 0 :(得分:2)
我从您的代码示例和您的评论中推断出,您不一定要将Glossy
类型传递给 getMemberInfo
,但关键要求是您要执行网络请求并返回Glossy
类型。
虽然我得到了你想要做的事情,但我个人会退出通用方法,只使用protocol extension。您最终会得到一个可以为任何Glossy
类型调用的方法。如果此协议扩展方法返回类型Self
,那么最终将返回您恰好称之为的Glossy
类型。
首先,让我们退一步,明确Glossy
协议可能是什么样子。至少,你有一些可用的初始化程序(以及你需要的其他类型):
protocol Glossy {
init?(json: [String: AnyObject])
}
(注意,我没有使用JSON
类型,但如果你愿意,可以随意使用。我个人只是使用Swift集合来解析JSON,但是做任何你想做的事。)
然后我在协议扩展中定义static
方法来执行请求。以下方法使用NSURLSession
,但如果您使用Alamofire或其他方法,基本想法是相同的:
extension Glossy {
static func performMemberRequest(memberDataRequest: String, completionHandler:(Self?, ErrorType?) -> ()) -> NSURLSessionTask {
let urlAccess = "\(baseURL)/api/\(memberDataRequest)"
let request = NSMutableURLRequest(URL: NSURL(string: urlAccess)!)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, response, error in
guard let data = data where error == nil else {
completionHandler(nil, error)
return
}
do {
if let array = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? [[String: AnyObject]],
let dictionary = array.first {
completionHandler(Self(json: dictionary), nil)
} else {
completionHandler(nil, GlossyError.InvalidJSONError)
}
} catch let parseError {
completionHandler(nil, parseError)
}
}
task.resume()
return task
}
}
请注意,上述内容中存在一些值得注意的问题:
网络请求应始终异步执行。因此,请使用completionHandler
之类的异步模式,而不是尝试立即返回某个对象。
如果您要返回任何内容,那么您应该返回的唯一内容是NSURLSessionTask
对象,因此如果您需要该功能,调用者可以选择捕获并取消请求。
我将方法的名称更改为更具描述性并符合Cocoa命名约定。
顺便说一句,您的代码建议您的API返回一个数组,而您只是抓住第一个字典。这似乎是一种奇怪的模式,但我已经在上面跟着它了。如果你真的要返回一个数组,那么你会这样做,因为你考虑了一个你可以返回多个项目的场景。在这种情况下,我建议迭代整个数组并让完成处理程序返回[Self]?
(Glossy
个对象的数组),而不仅仅是Self?
(即只有第一个)。
此外,我不会亲自建议将数组作为顶级项返回的结构。该Web服务如何报告错误?我有一个字典结构返回成功/失败和/或返回代码等。然后有一个专用的结果键,这将是你的结果数组。
但我没有解决上述任何更广泛的API问题,而是遵循代码段中的模式。但这些是您可能想要考虑的因素。
在我的示例中,我没有将这些completionHandler
调用发送回主队列,但这通常是非常有用的模式(避免同步问题,UI更新等) )。这样做很简单,但我想保持上述相对简单。
但是,让我们从您的API等细节中剔除。让我们关注您希望在协议扩展中定义static
方法的概念(因此可以从符合Glossy
的任何类型调用它)。例如,我可以使用所需的初始化程序定义LoyaltyCard
类:
struct LoyaltyCard: Glossy {
let id: Int
init?(json: [String: AnyObject]) {
guard let id = json["id"] as? Int else {
return nil
}
self.id = id
}
}
完成所有这些后,我现在可以在static
上调用Glossy
LoyaltyCard
协议扩展方法,例如:
LoyaltyCard.performMemberRequest(memberDataRequest) { loyaltyCard, error in
guard let loyaltyCard = loyaltyCard where error == nil else {
print(error)
return
}
// do something with loyaltyCard here
print(loyaltyCard)
}
// but don't use it here
那里有很多,但我不希望你迷失在细节中。但是我希望你在这里理解关键概念:不要将Glossy
类型传递给你的方法,也不要使用泛型:而是使用协议扩展。并避免同步网络请求,因此请使用类似completionHandler
模式的异步模式。