EXC_BAD_ACCESS在Swift中使用generics
相关的问题: 在Swift中的通用完成处理程序
在我正在写的Swift应用程序中,我正在下载JSON,我想将其转换为模型对象。 现在,我正在这样做:
func convertJSONData<T: Entity>(jsonData: NSData?, jsonKey: JSONKey, _: T.Type) -> [T]? { var entities = [T]() if let data = jsonData { // Left out error checking for brevity var json = JSON(data: data, options: nil, error: nil) var entitiesJSON = json[jsonKey.rawValue] for (index: String, subJson: JSON) in entitiesJSON { // Error: EXC_BAD_ACCESS(code=EXC_I386_GPFLT) let entity = T(json: subJson) entities.append(entity) } } return entities }
符合Entity
每个对象实现init(json: JSON)
。 JSON
是SwiftyJSON库中定义的一种types。 这也是枚举看起来有点奇怪的原因。
我用这个方法调用convertJSONData()
:
public func performJSONRequest<T where T: Entity>(jsonRequest: JSONRequest<T>) { var urlString = ... Alamofire.request(.GET, urlString, parameters: nil, encoding: .JSON).response { (request, response, data, error) -> Void in var books = self.convertJSONData(data as? NSData, jsonKey: jsonRequest.jsonKey, T.self) jsonRequest.completionHandler(books, error) } }
我得到了一个调用T(json: subJSON)
错误EXC_BAD_ACCESS(code=EXC_I386_GPFLT)
错误。 没有编译器警告或错误。 虽然我没有在上面的代码中检查错误,但在实际的代码中有错误检查, error
是零。
我不确定这是一个编译器错误还是我的错,任何帮助指出这是非常赞赏。
有几件事情正在发生,我怀疑问题在于实现Entity
协议的类的初始化器中。
假设代码类似于以下内容:
protocol Entity { init(json: JSON) } class EntityBase: Entity { var name: String = "" required init(json: JSON) { // required keyword is vital for correct type inference if let nameFromJson = json["name"].string { self.name = nameFromJson } } func getName() -> String { return "Base with \(name)" } } class EntitySub: EntityBase { convenience required init(json: JSON) { self.init(json: json) // the offending line } override func getName() -> String { return "Sub with \(name)" } }
该代码在子类中使用self.init(json: json)
进行编译,但实际上试图使用便捷方法初始化实例导致EXC_BAD_ACCESS
。
要么删除子类上的初始化器,要么简单地实现required init
和超级调用。
class EntitySub: EntityBase { required init(json: JSON) { super.init(json: json) } override func getName() -> String { return "Sub with \(name)" } }
将jsonData
转换为Entity
(当jsonData
nil
时jsonData
修改以.None
jsonData
):
func convertJSONData<T:Entity>(jsonData: NSData?, jsonKey: JSONKey, type _:T.Type) -> [T]? { if let jsonData = jsonData { var entities = [T]() let json = JSON(data: jsonData, options:nil, error:nil) let entitiesJSON = json[jsonKey.rawValue] for (index:String, subJson:JSON) in entitiesJSON { let entity:T = T(json: subJson) entities.append(entity) } return entities } return .None }