EXC_BAD_ACCESS using Generics in Swift

Related question: General completion handler in Swift

In the Swift application I am writing, I load JSON and I want to convert it to model objects. Right now, I'm doing it 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 entity corresponding to Entity implements init(json: JSON) . JSON is a type defined in the SwiftyJSON library. This is also the reason the listing looks a bit odd.

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 an EXC_BAD_ACCESS(code=EXC_I386_GPFLT) runtime EXC_BAD_ACCESS(code=EXC_I386_GPFLT) causing T(json: subJSON) . There are no warnings or compiler errors. Although I left error checking in the above code, there is error checking in the actual code, and error is zero.

I am not sure if this is a compiler error or my mistake, and any help is that it is very valuable.

+5
source share
1 answer

Several things happen here, and I suspect that the problem lies somewhere in the initializer of the class that implements 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 a subclass, but actually trying to initialize an instance using the convenience method results in EXC_BAD_ACCESS .

Either remove the initializer in the subclass, or simply implement the 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 for converting jsonData to Entity (slightly modified to 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 } 
+3
source

Source: https://habr.com/ru/post/1208526/


All Articles