EXC_BAD_ACCESS在Swift中使用泛型 [英] EXC_BAD_ACCESS using Generics in Swift

查看:156
本文介绍了EXC_BAD_ACCESS在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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆