Core Data is crashing when doing a fetch request but I can't understand why. The error is suggesting EXC_BAD_ACCESS but it doesn't always occur for this particular fetch request. Basically when I zoom in and out on the mapView (MKMapKit), it's at that point it crashes.
For my mapView I use the following code:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let userStatus = CoreDataUserLocationManagement().returnUsersLastKnownStatus()
if (annotation is MKUserLocation) && userStatus != 3 {
As you can see from the above, this is when I request the lastKnownStatus, but as mentioned it doesn't always crash.
This fetch crashes here
func returnUsersLastKnownStatus() -> Int16 {
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "UsersLocationDetails")
do {
if let fetchResults = try managedObjectContext.fetch(fetchRequest) as? [UsersLocationDetails] {
if fetchResults.count != 0 {
let managedObject = fetchResults[0]
return managedObject.lastKnownStatus
}
}
}
catch {
print("Catch error retrieving last known status to Core Data")
}
return 3
}
The log is:
Printing description of fetchRequest:
(NSFetchRequest) fetchRequest = 0x0000000283a5be20 {
baseNSPersistentStoreRequest#0 = {
baseNSObject#0 = {
isa = NSFetchRequest
}
_affectedStores = 0x0000000000000000
}
_groupByProperties = 0x0000000000000000
_havingPredicate = 0x0000000000000000
_additionalPrivateIvars = 0x0000000281044100
_valuesToFetch = 0x0000000000000000
_entity = 0x0000000282684dc0 {
baseNSObject#0 = {
isa = NSEntityDescription
}
_cd_rc = 12
_snapshotClass = 0x000000028208a760
_versionHashModifier = 0x0000000000000000
_versionHash = some {
some = 0x0000000102faea90 {
baseNSData#0 = {
baseNSObject#0 = {
isa = _PFEncodedData
}
}
_aData = some {
some = 0x00000002811c7e60 {
baseNSData#0 = {
baseNSObject#0 = {
isa = _PFVMData
}
}
_cd_rc = 1732
_length = 40944
_payload = 0x0000000102fac000
}
}
_byteCount = 32
_reserved = 0
}
}
_model = some {
some = 0x00000002832a9400 {
baseNSObject#0 = {
isa = NSManagedObjectModel
}
_dataForOptimization = some {
some = 0x00000002811c7e60 {...}
}
_optimizationHints = 0x0000000102fb5850
_additionalPrivateIvars = 0x00000002811c0120
_entities = some {
some = 0x000000028239f9f0 {
baseNSKnownKeysDictionary1#0 = {
baseNSKnownKeysDictionary#0 = {
baseNSMutableDictionary#0 = {
NSDictionary = {
NSObject = {
isa = NSKnownKeysDictionary2
}
}
}
}
_cd_rc = 0
_count = 14
_keySearch = some {
some = 0x0000000102faeb10 {
baseNSKnownKeysMappingStrategy1#0 = {
baseNSKnownKeysMappingStrategy#0 = {
baseNSObject#0 = {
isa = NSKnownKeysMappingStrategy2
}
}
_cd_rc = -2128839072
_reserved64 = 2
_table = 0x0000000102faeb40
_length = 14
_reserved1 = 0x0000000000000000
_keys = 0x0000000102faec28
}
}
}
_values = {}
}
}
}
_configurations = 0x00000002811c0100 1 key/value pair
_fetchRequestTemplates = 0x0000000000000000
_versionIdentifiers = 0x00000002811c0140 1 element
}
}
_classNameForEntity = some {
some = 0x0000000102fad388 {
base_PFAbstractString#0 = {
baseNSString#0 = {
baseNSObject#0 = {
isa = _PFEncodedString
}
}
}
_cd_rc = 0
_length = 20
_sourceData = some {
some = 0x00000002811c7e60 {...}
}
}
}
_instanceClass = 0x00000002835b9b70
_name = some {
some = 0x0000000102fad388 {...}
}
_rootentity = 0x0000000282684dc0 {...}
_superentity = 0x0000000000000000
_subentities = 0x0000000000000000
_properties = some {
some = 0x00000002835b8720 {
baseNSKnownKeysDictionary1#0 = {
baseNSKnownKeysDictionary#0 = {
baseNSMutableDictionary#0 = {
NSDictionary = {
NSObject = {
isa = NSKnownKeysDictionary2
}
}
}
}
_cd_rc = 0
_count = 9
_keySearch = some {
some = 0x0000000102fb0bf0 {
baseNSKnownKeysMappingStrategy1#0 = {
baseNSKnownKeysMappingStrategy#0 = {
baseNSObject#0 = {
isa = NSKnownKeysMappingStrategy2
}
}
_cd_rc = -2128839072
_reserved64 = 2
_table = 0x0000000102fb0c20
_length = 9
_reserved1 = 0x0000000000000000
_keys = 0x0000000102fb0cd0
}
}
}
_values = {}
}
}
}
_propertyMapping = some {
some = 0x0000000102fb0bf0 {...}
}
_userInfo = 0x0000000000000000
_flattenedSubentities = 0x0000000281ff60d0 1 element
_kvcPropertyAccessors = 0x00000002832a92c0
_modelsReferenceIDForEntity = 13
}
_predicate = 0x0000000000000000
_sortDescriptors = 0x0000000000000000
_batchSize = 0
_fetchLimit = 0
_allocationSize = 0
_relationshipKeyPathsForPrefetching = 0x0000000000000000
}
Also just noticed this in Xcode:
(NSPersistentStoreRequest) CoreData.NSPersistentStoreRequest = <parent failed to evaluate: invalid load address>
So it turns out that it was this piece of code that code that was causing the issue. I have no idea why as the crash wasn't reporting this but as soon as I commented it out, it no longer crashes.
#IBAction func centerUserBtnTapped(_ sender: Any) {
let location = CLLocationCoordinate2D(latitude: locationManager.location?.coordinate.latitude ?? 0.0, longitude: locationManager.location?.coordinate.longitude ?? 0.0)
let span = MKCoordinateSpan.init(latitudeDelta: self.mapView.region.span.latitudeDelta, longitudeDelta: self.mapView.region.span.longitudeDelta)
let region = MKCoordinateRegion(center: location, span: span)
self.mapView.setRegion(region, animated: true)
self.mapView.setUserTrackingMode(.follow, animated: true)
}
Instead I simplified it to the normal approach:
#IBAction func centerUserBtnTapped(_ sender: Any) {
mapView.setUserTrackingMode(.follow, animated: true)
}
I have an Expense entity with a one-to-many relationship to an Accounts Entity.
My current fetch request is as follows:
let request = NSFetchRequest<NSFetchRequestResult>(entityName: Expenses.entity().name ?? "Expenses")
request.predicate = predicate
request.returnsObjectsAsFaults = false
request.resultType = .dictionaryResultType
let expression = NSExpressionDescription()
// check operations list from apple or nshipster in nsexpressions
expression.expression = NSExpression(forFunction: "noindex:", arguments:[NSExpression(forKeyPath: "originAccounts.isCredit")])
expression.name = "checkIsCredit"
expression.expressionResultType = .booleanAttributeType // might be another
let expression1 = NSExpressionDescription()
expression1.expression = NSExpression(forFunction: "noindex:", arguments:[NSExpression(forKeyPath: "id")])
expression1.name = "checkExpenses"
expression.expressionResultType = .UUIDAttributeType
request.propertiesToFetch = [expression,expression1]
context.perform {
do {
let results = try request.execute()
print(results)
My Predicate is:
predicate: NSPredicate(format: "expenseDate >= %# AND expenseDate < %#", datesView.prevMonthPayStart as NSDate, datesView.nextPaydate as NSDate)
When I print the results I get
[{
expenseAccount = "Test Account";
expenseCategory = "Test Category";
expenseCost = 123;
expenseDate = "2020-11-12 05:00:00 +0000";
expenseIsPaid = 1;
expenseName = Test;
expenseType = "One-time";
id = "AFB5EB0E-20A2-47EA-8F36-22D07571C213";
shouldDupe = 1;
}, {
expenseAccount = "Test Account";
expenseCategory = "Test Category";
expenseCost = 23;
expenseDate = "2020-11-13 05:00:00 +0000";
expenseIsPaid = 0;
expenseName = "Test Recurring";
expenseType = Monthly;
id = "5CFB5E58-4377-40DA-9C6A-AF8027ACEC60";
shouldDupe = 1;
}]
I understand that I won't see attributes that are nil, but I want to get an attribute through originAccounts relationship. Is this possible? Specifically I want to get the value of originAccounts.isCredit. Here is an example object for reference.
<Expenses: 0x60000321af80> (entity: Expenses; id: 0xa7ab05bb9341bf4a <x-coredata://ED302202-3018-445F-8FFE-DD2E85219E64/Expenses/p1>; data: {
expenseAccount = "Test Account";
expenseCategory = "Test Category";
expenseCost = 123;
expenseDate = "2020-11-12 05:00:00 +0000";
expenseId = nil;
expenseIsPaid = 1;
expenseName = Test;
expenseType = "One-time";
id = "AFB5EB0E-20A2-47EA-8F36-22D07571C213";
lastMonthlyExpenseID = nil;
nextMonthlyExpenseID = nil;
originAccounts = "0xa7ab05bb9341bf4e <x-coredata://ED302202-3018-445F-8FFE-DD2E85219E64/Accounts/p1>";
originCategories = nil;
shouldDupe = 1;
})
Could you try NSExpressions, you won't make a fetch, therefore you'll be mutch efficient.
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "yourEntity")
fetchRequest.predicate = NSPredicate(format: "yourPredicate")
fetchRequest.resultType = .dictionaryResultType
fetchRequest.returnsObjectsAsFaults = false
let expression = NSExpressionDescription()
// check operations list from apple or nshipster in nsexpressions
expression.expression = NSExpression(forFunction: "yourOperation", arguments:[NSExpression(forKeyPath: "Expenses.originAccounts.isCredit")])
expression.name = "yourName"
expression.expressionResultType = .decimalAttributeType // might be another
fetchRequest.propertiesToFetch = [expression]
do {
let results = try viewContext.fetch(fetchRequest)
print(results)
} catch {
print("Failed to fetch aggregates")
}
}
please help on this error message:
While silgen emitFunction SIL function "#$S6QRCart6CartVCC9tableView_12cellForRowAtSo07UITableE4CellCSo0jE0C_10Foundation9IndexPathVtF".
for 'tableView(_:cellForRowAt:)' at /Users/Stenly/Downloads/QRCartGeo/QRCart/CartVC.swift:89:5
error: Segmentation fault: 11
This is my code:
func tableView(_ tableView: UITableView, cellForRowAt indePath: IndexPath) -> UITableViewCell {
// Parents
let cellIdentifierParents = "cell"
let CartCell: CartCell? = tableView.dequeueReusableCell(withIdentifier: cellIdentifierParents) as? CartCell
let cellObject = loadedCart[indePath.row]
CartCell?.selectionStyle = .none
CartCell?.lblItem.text = (cellObject as AnyObject).object(forKey: "item") as? String
CartCell?.lblSize.text = (cellObject as AnyObject).object(forKey: "size") as? String
CartCell?.lblPrice.text = ((cellObject as AnyObject).object(forKey: "price") as? String!)! + " €"
CartCell?.lblPrice.text = CartCell?.lblPrice.text?.replacingOccurrences(of: ".", with: ",")
var total = Float()
for item in loadedCart {
let price : NSString = ((item as AnyObject).object(forKey: "price") as? NSString)!
let priceTruncate = price.replacingOccurrences(of: "€", with: "")
let a:Float? = Float(priceTruncate)
total = total + a!
self.lblTotalOfCart.text = String(format : "SE: %.2f €",total)
self.lblTotalOfCart.text = self.lblTotalOfCart.text?.replacingOccurrences(of: ".", with: ",")
}
let deleteItem = UITapGestureRecognizer(target: self, action: #selector(self.deleteItem(_:)))
CartCell?.btnRemoveOutlet.addGestureRecognizer(deleteItem)
CartCell?.btnRemoveOutlet.isUserInteractionEnabled = true;
return CartCell!
}
I have created a grouped bar chart with pretty simple values. I have 5 labels which I would like spread out along the xaxis and 3 bar groups to coincide with each xaxis label.
The graph right now shows 1 xaxis label and 1 bar. (they may be out of frame, it's hard to tell.) I need each case to sync up with the correct msArrayAxis label.
Here is the code:
var msArrayXAxis = ["0-20", "20-50", "50-100", "100-200", "<200"]
barchartView.isUserInteractionEnabled = false
barchartView.noDataText = "You need to provide data for the chart."
barchartView.legend.enabled = false
barchartView.chartDescription?.text = ""
barchartView.xAxis.labelPosition = XAxis.LabelPosition.bottom
barchartView.xAxis.valueFormatter = IndexAxisValueFormatter(values: msArrayXAxis)
barchartView.xAxis.axisMinimum = 0
barchartView.xAxis.granularity = 2
barchartView.xAxis.setLabelCount(5, force: true)
barchartView.xAxis.spaceMin = 0.3
// barchartView.extraBottomOffset = 1
barchartView.xAxis.labelWidth = 1
barchartView.xAxis.avoidFirstLastClippingEnabled = true
barchartView.rightAxis.drawGridLinesEnabled = false
barchartView.rightAxis.drawAxisLineEnabled = false
barchartView.rightAxis.drawLabelsEnabled = false
func parsedArrayCount(case1: Array<Double>,case2: Array<Double>,case3: Array<Double>,case4: Array<Double>, case5: Array<Double>) -> [BarChartDataEntry] {
var dataEntries1: [BarChartDataEntry] = []
NSLog("Parsing array count")
let dataEntry = BarChartDataEntry(x: Double(0), y:Double(case1.count))
dataEntries1.append(dataEntry)
let dataEntry2 = BarChartDataEntry(x: Double(1), y:Double(case2.count))
dataEntries1.append(dataEntry2)
let dataEntry3 = BarChartDataEntry(x: Double(2), y:Double(case3.count))
dataEntries1.append(dataEntry3)
let dataEntry4 = BarChartDataEntry(x: Double(3), y:Double(case4.count))
dataEntries1.append(dataEntry4)
let dataEntry5 = BarChartDataEntry(x: Double(1), y:Double(case5.count))
dataEntries1.append(dataEntry5)
return dataEntries1
}
func updateGraph(array: Array<name>?) {
var dataEntries1: [BarChartDataEntry] = []
var dataEntries2: [BarChartDataEntry] = []
var dataEntries3: [BarChartDataEntry] = []
barchartView.clear()
rArray.removeAll()
nameArray.removeAll()
if array != nil && array!.count > 0 {
for i in 0..<array!.count {
rArray.append(array![i].r)
nameArray.append(array![i].name)
}
NSLog("updating graph..")
let name = Analyzer.sharedInstance.nameArray(names: rArray.map{String($0)}, Name: nameArray)
let cData = parserArrays(rArray: name.first.map {Double($0)!})
let wData = parserArrays(rArray: name.last.map {Double($0)!})
let vData = parserArrays(rArray: name.middle.map {Double($0)!})
dataEntries1 = parsedArrayCount(case1: cData.case1, case2: cData.case2, case3: cData.case3, case4: cData.case4, case5: cData.case5)
dataEntries2 = parsedArrayCount(case1: wData.case1, case2: wData.case2, case3: wData.case3, case4: wData.case4, case5: wData.case5)
dataEntries3 = parsedArrayCount(case1: vData.case1, case2: vData.case2, case3: vData.case3, case4: vData.case4, case5: vData.case5)
let chartDataSet = BarChartDataSet(values: dataEntries1, label: "")
chartDataSet.colors = [UIColor.Blue()]
let chartDataSet1 = BarChartDataSet(values: dataEntries2, label: "")
chartDataSet1.colors = [UIColor.Green()]
let chartDataSet2 = BarChartDataSet(values: dataEntries3, label: "")
chartDataSet2.colors = [UIColor.Orange()]
NSLog("Data set1 \(dataEntries1)")
let groupSpace = 1.0
let barSpace = 0.05
let barWidth = 0.1
/* let xAxis = XAxis()
xAxis.valueFormatter = self
xAxis.drawGridLinesEnabled = true
xAxis.labelPosition = .bottom
xAxis.centerAxisLabelsEnabled = true
barchartView.xAxis.valueFormatter = xAxis.valueFormatter*/
let dataSets: [BarChartDataSet] = [chartDataSet,chartDataSet1]
let chartData = BarChartData(dataSets: dataSets)
chartData.setDrawValues(false)
chartData.barWidth = barWidth
chartData.groupBars(fromX:0.3, groupSpace: groupSpace, barSpace: barSpace)
// let gg = chartData.groupWidth(groupSpace: groupSpace, barSpace: barSpace)
// barchartView.xAxis.axisMaximum = Double(0) + gg * Double(msArrayXAxis.count)
barchartView.data = chartData
barchartView.animate(yAxisDuration: 0.5)
}
}
Please check :
var msArrayXAxis = ["0-20", "20-50", "50-100", "100-200", "<200"]
barChartView.isUserInteractionEnabled = false
barChartView.noDataText = "You need to provide data for the chart."
barChartView.legend.enabled = false
barChartView.chartDescription?.text = ""
barChartView.xAxis.labelPosition = XAxis.LabelPosition.bottom
barChartView.xAxis.valueFormatter = IndexAxisValueFormatter(values: msArrayXAxis)
barChartView.xAxis.axisMinimum = 0
barChartView.xAxis.granularity = 1
barChartView.xAxis.labelCount = msArrayXAxis.count
barChartView.xAxis.centerAxisLabelsEnabled = true
barChartView.xAxis.spaceMin = 0.3
barChartView.xAxis.labelWidth = 1
barChartView.rightAxis.drawGridLinesEnabled = false
barChartView.rightAxis.drawAxisLineEnabled = false
barChartView.rightAxis.drawLabelsEnabled = false
func parsedArrayCount(case1: Array<Double>,case2: Array<Double>,case3: Array<Double>,case4: Array<Double>, case5: Array<Double>) -> [BarChartDataEntry] {
var dataEntries1: [BarChartDataEntry] = []
NSLog("Parsing array count")
let dataEntry = BarChartDataEntry(x: Double(0), y:Double(case1.count))
dataEntries1.append(dataEntry)
let dataEntry2 = BarChartDataEntry(x: Double(1), y:Double(case2.count))
dataEntries1.append(dataEntry2)
let dataEntry3 = BarChartDataEntry(x: Double(2), y:Double(case3.count))
dataEntries1.append(dataEntry3)
let dataEntry4 = BarChartDataEntry(x: Double(3), y:Double(case4.count))
dataEntries1.append(dataEntry4)
let dataEntry5 = BarChartDataEntry(x: Double(1), y:Double(case5.count))
dataEntries1.append(dataEntry5)
return dataEntries1
}
func updateGraph() {
var dataEntries1: [BarChartDataEntry] = []
var dataEntries2: [BarChartDataEntry] = []
var dataEntries3: [BarChartDataEntry] = []
barChartView.clear()
NSLog("updating graph..")
let name = Analyzer.sharedInstance.nameArray(names: rArray.map{String($0)}, Name: nameArray)
let cData = parserArrays(rArray: name.first.map {Double($0)!})
let wData = parserArrays(rArray: name.last.map {Double($0)!})
let vData = parserArrays(rArray: name.middle.map {Double($0)!})
dataEntries1 = parsedArrayCount(case1: cData.case1, case2: cData.case2, case3: cData.case3, case4: cData.case4, case5: cData.case5)
dataEntries2 = parsedArrayCount(case1: wData.case1, case2: wData.case2, case3: wData.case3, case4: wData.case4, case5: wData.case5)
dataEntries3 = parsedArrayCount(case1: vData.case1, case2: vData.case2, case3: vData.case3, case4: vData.case4, case5: vData.case5)
let chartDataSet = BarChartDataSet(values: dataEntries1, label: "")
chartDataSet.colors = [UIColor.blue]
let chartDataSet1 = BarChartDataSet(values: dataEntries2, label: "")
chartDataSet1.colors = [UIColor.green]
let chartDataSet2 = BarChartDataSet(values: dataEntries3, label: "")
chartDataSet2.colors = [UIColor.orange]
NSLog("Data set1 \(dataEntries1)")
let groupSpace = 0.1
let barSpace = 0.05
let barWidth = 0.25
let dataSets: [BarChartDataSet] = [chartDataSet,chartDataSet1, chartDataSet2]
let chartData = BarChartData(dataSets: dataSets)
chartData.setDrawValues(false)
chartData.barWidth = barWidth
let gg = chartData.groupWidth(groupSpace: groupSpace, barSpace: barSpace)
barChartView.xAxis.axisMaximum = Double(0) + gg * Double(msArrayXAxis.count)
chartData.groupBars(fromX:0.0, groupSpace: groupSpace, barSpace: barSpace)
barChartView.notifyDataSetChanged()
barChartView.data = chartData
barChartView.animate(yAxisDuration: 0.5)
}
I need to list all properties of type LinkingObjects of a object.
class Dogs: Object {
dynamic var name: String = ""
dynamic var age: Int = 0
dynamic var owner: Persons?
}
class Cats: Object {
dynamic var name: String = ""
dynamic var age: Int = 0
dynamic var owner: Persons?
}
class Persons: Object {
dynamic var name: String = ""
dynamic var address: String = ""
let dogs = LinkingObjects(fromType: Dogs.self, property: "owner")
let cats = LinkingObjects(fromType: Cats.self, property: "owner")
}
ObjectSchema returns the schema correctly:
let person = Persons()
let schema = person.objectSchema
print(schema)
Result:
Persons {
name {
type = string;
objectClassName = (null);
linkOriginPropertyName = (null);
indexed = NO;
isPrimary = NO;
optional = NO;
}
address {
type = string;
objectClassName = (null);
linkOriginPropertyName = (null);
indexed = NO;
isPrimary = NO;
optional = NO;
}
dogs {
type = linking objects;
objectClassName = Dogs;
linkOriginPropertyName = owner;
indexed = NO;
isPrimary = NO;
optional = NO;
}
cats {
type = linking objects;
objectClassName = Cats;
linkOriginPropertyName = owner;
indexed = NO;
isPrimary = NO;
optional = NO;
}
}
However, objectSchema.properties does not return LinkingObjects properties.
let properties = schema.properties
print(properties)
Returns:
[name {
type = string;
objectClassName = (null);
linkOriginPropertyName = (null);
indexed = NO;
isPrimary = NO;
optional = NO;
}, address {
type = string;
objectClassName = (null);
linkOriginPropertyName = (null);
indexed = NO;
isPrimary = NO;
optional = NO;
}]
Where are the dogs and cats properties?
Thanks.
I found the solution:
let computedProperties = Persons.sharedSchema()?.computedProperties
The LinkingObjects properties are listed in the computedProperties property of RLMObjectSchema, which is currently not public or present on the Swift version of the class. While it's possible to get to the private property given an instance of the obj-c class (via .valueForKey("computedProperties")), that won't work on the Swift ones and there isn't any good way to get to the obj-c RLMObjectSchema when using Realm Swift.
There's an existing feature request to expose this.