EXC_BAD_ACCESS在Swift中使用泛型 [英] EXC_BAD_ACCESS using Generics in Swift
问题描述
相关问题: Swift中的通用完成处理程序
在我正在写的Swift应用程序中,我正在下载JSON并将其转换为模型对象。现在,我是这样做的:
func convertJSONData< T:Entity>(jsonData:NSData ?, jsonKey: JSONKey,_:T.Type) - > [T]? {
var entities = [T]()
如果让data = jsonData {
//遗漏错误检查以简化
var json = JSON(data:data,options:nil,error:nil)
var entitiesJSON = json [jsonKey.rawValue]
$ b for(index:String,subJson:JSON)entitiesJSON {
//错误:EXC_BAD_ACCESS(code = EXC_I386_GPFLT)
let entity = T(json:subJson)
entities.append(entity)
}
}
返回实体
}
符合 Entity
实现 init(json:JSON)
。 JSON
是在 SwiftyJSON 库中定义的类型。这也是枚举看起来有点奇怪的原因。
我在这个方法中调用 convertJSONData()
p>
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) - >无效
var books = self.convertJSONData(data as?NSData,jsonKey:jsonRequest.jsonKey,T.self)
jsonRequest.completionHandler(books,error)
}
}
我得到一个运行时 EXC_BAD_ACCESS(code = EXC_I386_GPFLT)
错误调用 T(json:subJSON)
。没有编译器警告或错误。虽然我没有在上面的代码中检查错误,但在实际代码中有错误检查, error
为零。
我不确定这是编译器错误还是我的错,并且非常感谢您的帮助。
解决方案这里有几件事情,我怀疑问题在于执行 Entity
协议的类的初始化程序中。
假设代码类似于以下内容:
协议实体{
init(json: JSON)
}
$ b $ class EntityBase:Entity {
var name:String =
需要init(json:JSON){//必需的关键字对于正确的类型推断
如果让nameFromJson = json [name]。string {
self.name = nameFromJson
}
}
func getName ) - > String {returnBase with \(name)}
}
$ b $ class EntitySub:EntityBase {
方便需要init(json:JSON){
self。 init(json:json)//违规行
}
覆盖func getName() - > String {returnSub with \(name)}
}
代码编译在子类中使用 self.init(json:json)
,但实际尝试使用便捷方法初始化实例导致 EXC_BAD_ACCESS
。
删除子类上的初始化器或者简单地执行所需的init
和调用super。
class EntitySub:EntityBase {
需要init(json:JSON){
super。 init(json:json)
}
覆盖func getName() - > String {returnSub with \(name)}
}
>
将 jsonData
转换为实体
(稍微修改以明确返回 .None
当 jsonData
nil
)时:
func convertJSONData< T:Entity>(jsonData:NSData?,jsonKey:JSONKey,type _:T.Type) - > [T]? {
if jsonData = jsonData {
var entities = [T]()
让json = JSON(data:jsonData,options:nil,error:nil)
让entitiesJSON = json [jsonKey.rawValue]
$ b $ for(index:String,subJson:JSON)in entitiesJSON {
let entity:T = T(json:subJson )
entities.append(entity)
}
返回实体
}
return .None
}
Related question: Generic completion handler in Swift
In a Swift app I'm writing, I'm downloading JSON and I want to convert it into model objects. Right now, I'm doing that like this:
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
}
Each object conforming to Entity
implements init(json: JSON)
. JSON
is a type defined in the SwiftyJSON library. That's also the reason the enumeration looks a bit weird.
I call convertJSONData()
in this method:
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)
}
}
I get a runtime EXC_BAD_ACCESS(code=EXC_I386_GPFLT)
error calling T(json: subJSON)
. There are no compiler warnings or errors. Although I left out error checking in the above code, there is error checking in the actual code and error
is nil.
I'm not sure whether this is a compiler bug or my fault and any help figuring that out is much appreciated.
Several things are going on here, and I suspect the problem lies somewhere in the initializer of the class implementing the Entity
protocol.
Assuming the code resembles the following:
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)" }
}
The code compiles with self.init(json: json)
in the sub-class, but actually trying to initialize the instance using the convenience method results in an EXC_BAD_ACCESS
.
Either remove the initializer on the sub-class or simply implement required init
and call super.
class EntitySub: EntityBase {
required init(json: JSON) {
super.init(json: json)
}
override func getName() -> String { return "Sub with \(name)" }
}
The method to convert the jsonData
to an Entity
(modified slightly to specifically return .None
when jsonData
is nil
):
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
}
这篇关于EXC_BAD_ACCESS在Swift中使用泛型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!