Reputation: 2317
I get an EXC_BAD_ACCESS
error when inserting an NSManagedObject at the superclass init
call. The error doesn't always occur, so my guess is that it has something to do with threading, however I'm very new to iOS development so I might be completely wrong.
In the code below I mark the line where the error occurs with a comment.
import Foundation
import CoreData
@objc(Measurement)
public class Measurement: NSManagedObject {
convenience init(sensorId: Int32, fromDatetime: Int64, pm10: Float, pm25: Float, airQualityIndex: Float32, pollutionLevel: Int16,
latitude: Double, longitude: Double, source: String, windDeg: Float32, windSpeed: Float32,
context: NSManagedObjectContext) {
if let ent = NSEntityDescription.entity(forEntityName: "Measurement", in: context) {
self.init(entity: ent, insertInto: context) // Thread 10: EXC_BAD_ACCESS (code=1, address=0xfffffffc)
self.fromDatetime = fromDatetime
self.pm10 = pm10
// omitted value asignments
} else {
fatalError("Unable to find entity name Measurement")
}
}
}
The inserting happens after a call to an api inside a for loop.
let task = session.dataTask(with: request) { (data, response, error) in
// if an error occurs, print it and re-enable the UI
func displayError(_ error: String) {
print(error)
}
/* GUARD: Was there an error? */
guard (error == nil) else {
displayError("There was an error with your request: \(String(describing: error))")
return
}
/* GUARD: Did we get a successful 2XX response? */
guard let statusCode = (response as? HTTPURLResponse)?.statusCode, statusCode >= 200 && statusCode <= 299 else {
displayError("Your request returned a status code other than 2xx!")
return
}
/* GUARD: Was there any data returned? */
guard let data = data else {
displayError("No data was returned by the request!")
return
}
// parse the data
let parsedResult: [[String:AnyObject]]!
do {
parsedResult = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [[String:AnyObject]]
} catch {
displayError("Could not parse the data as JSON: '\(data)'")
return
}
let delegate = UIApplication.shared.delegate as! AppDelegate
let stack = delegate.stack
var counter = 0
for measurement in parsedResult {
if counter == 0 {
print(measurement)
}
guard let sensorId = measurement[Constants.MeasurementModelKeys.sensorId] as? Int32 else {
print("Cannot find key 'sensor_id' in \(measurement)")
continue
}
// other guarded assignments ...
_ = Measurement(sensorId: sensorId, fromDatetime: fromDatetime, pm10: pm10, pm25: pm25,
airQualityIndex: airQualityIndex, pollutionLevel: pollutionLevel, latitude: latitude, longitude: longitude,
source: source, windDeg: windDeg, windSpeed: windSpeed,
context: stack.context) // << this is where the insertion happens
counter += 1
}
print("counter counted: \(counter) elements")
}
// start the task!
task.resume()
}
Any help is much appreciated (including tips on how to track down the exact cause of the error).
Upvotes: 0
Views: 141
Reputation: 5563
Core Data is indeed very touchy about threading. Inserting new objects in a context should be performed on that context queue.
Try this :
stack.context.perform {
_ = Measurement(sensorId: sensorId, fromDatetime: fromDatetime, pm10: pm10, pm25: pm25,
airQualityIndex: airQualityIndex, pollutionLevel: pollutionLevel, latitude: latitude, longitude: longitude,
source: source, windDeg: windDeg, windSpeed: windSpeed,
context: stack.context)
}
Note that this is now an asynchronous call. Make sure this doesn't break your code somewhere else.
Upvotes: 1