I'm having trouble simply inserting an NSManagedObject with a to-one relationship when using Swift on Xcode 6b3.
I put my repro on GitHub but the failing code (in SwiftCoreDataRelationshipReproTests.swift's testSwiftToOne unit test method) boils down to this:
let momURL : NSURL = NSBundle.mainBundle().URLForResource("SwiftCoreDataRelationshipRepro",
withExtension: "momd")
let mom : NSManagedObjectModel = NSManagedObjectModel(contentsOfURL: momURL)
let psc : NSPersistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: mom);
let ps : NSPersistentStore = psc.addPersistentStoreWithType(
NSInMemoryStoreType,
configuration: nil,
URL: nil,
options: nil,
error: nil)
let moc : NSManagedObjectContext = NSManagedObjectContext()
moc.persistentStoreCoordinator = psc
// This throws an NSInvalidArgumentException: "An NSManagedObject of class 'NSManagedObject' must have a valid NSEntityDescription."
NSManagedObject(
entity: NSEntityDescription.entityForName("Pet", inManagedObjectContext: moc),
insertIntoManagedObjectContext: moc)
That seems like it should work. Nothing tricky.
My very similar Person entity with a to-many relationship can be inserted (and saved) correctly with Swift (as evidenced in the passing testSwiftToMany test) . The more-complicated Objective-C version also succeeds with the same data model (the passing testObjcToOneAndToMany test).
Here's the entire exception:
file:///%3Cunknown%3E: test failure: -[SwiftCoreDataRelationshipReproTests testSwiftToOne()] failed: failed: caught "NSInvalidArgumentException", "An NSManagedObject of class 'NSManagedObject' must have a valid NSEntityDescription."
(
0 CoreFoundation 0x00007fff8dd6525c __exceptionPreprocess + 172
1 libobjc.A.dylib 0x00007fff84ce5e75 objc_exception_throw + 43
2 CoreData 0x00007fff8765dd16 -[NSManagedObject initWithEntity:insertIntoManagedObjectContext:] + 550
3 SwiftCoreDataRelationshipReproTests 0x0000000100394d4a _TTOFCSo15NSManagedObjectcfMS_FT6entityGSQCSo19NSEntityDescription_30insertIntoManagedObjectContextGSQCSo22NSManagedObjectContext__S_ + 42
4 SwiftCoreDataRelationshipReproTests 0x00000001003946bd _TFCSo15NSManagedObjectCfMS_FT6entityGSQCSo19NSEntityDescription_30insertIntoManagedObjectContextGSQCSo22NSManagedObjectContext__S_ + 93
5 SwiftCoreDataRelationshipReproTests 0x0000000100393450 _TFC35SwiftCoreDataRelationshipReproTests35SwiftCoreDataRelationshipReproTests14testSwiftToOnefS0_FT_T_ + 816
6 SwiftCoreDataRelationshipReproTests 0x00000001003934c2 _TToFC35SwiftCoreDataRelationshipReproTests35SwiftCoreDataRelationshipReproTests14testSwiftToOnefS0_FT_T_ + 34
7 CoreFoundation 0x00007fff8dc50a5c __invoking___ + 140
8 CoreFoundation 0x00007fff8dc508c4 -[NSInvocation invoke] + 308
9 XCTest 0x00000001003b023a -[XCTestCase invokeTest] + 253
10 XCTest 0x00000001003b03ac -[XCTestCase performTest:] + 142
11 XCTest 0x00000001003b8ad0 -[XCTest run] + 257
12 XCTest 0x00000001003af68b -[XCTestSuite performTest:] + 379
13 XCTest 0x00000001003b8ad0 -[XCTest run] + 257
14 XCTest 0x00000001003af68b -[XCTestSuite performTest:] + 379
15 XCTest 0x00000001003b8ad0 -[XCTest run] + 257
16 XCTest 0x00000001003af68b -[XCTestSuite performTest:] + 379
17 XCTest 0x00000001003b8ad0 -[XCTest run] + 257
18 XCTest 0x00000001003acc8f __25-[XCTestDriver _runSuite]_block_invoke + 56
19 XCTest 0x00000001003b773d -[XCTestObservationCenter _observeTestExecutionForBlock:] + 162
20 XCTest 0x00000001003acbc8 -[XCTestDriver _runSuite] + 269
21 XCTest 0x00000001003ad34a -[XCTestDriver _checkForTestManager] + 551
22 XCTest 0x00000001003bb879 +[XCTestProbe runTests:] + 175
23 Foundation 0x00007fff8e0aacb7 __NSFireDelayedPerform + 333
24 CoreFoundation 0x00007fff8dccc494 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 20
25 CoreFoundation 0x00007fff8dccbfcf __CFRunLoopDoTimer + 1151
26 CoreFoundation 0x00007fff8dd3d5aa __CFRunLoopDoTimers + 298
27 CoreFoundation 0x00007fff8dc87755 __CFRunLoopRun + 1525
28 CoreFoundation 0x00007fff8dc86f25 CFRunLoopRunSpecific + 309
29 HIToolbox 0x00007fff8e566a0d RunCurrentEventLoopInMode + 226
30 HIToolbox 0x00007fff8e566685 ReceiveNextEventCommon + 173
31 HIToolbox 0x00007fff8e5665bc _BlockUntilNextEventMatchingListInModeWithFilter + 65
32 AppKit 0x00007fff8538e26e _DPSNextEvent + 1434
33 AppKit 0x00007fff8538d8bb -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 122
34 AppKit 0x00007fff853819bc -[NSApplication run] + 553
35 AppKit 0x00007fff8536c7a3 NSApplicationMain + 940
36 SwiftCoreDataRelationshipRepro 0x000000010000ad55 top_level_code + 37
37 SwiftCoreDataRelationshipRepro 0x000000010000ad8a main + 42
38 libdyld.dylib 0x00007fff861115fd start + 1
)
So I couldn't solve the problem, but I think I narrowed it down to a bug in the framework or Swift. Using entityForName is equivalent to getting the entity directly out of the managedObjectModel so I tried to do it that way:
let entities = moc.persistentStoreCoordinator.managedObjectModel.entitiesByName;
let keys = Array(entities.keys)
let petVar : String = keys[1] as String
let isEqual1 = (petVar == "Pet") // true
let isEqual2 = (petVar.hashValue == "Pet".hashValue) // true
let result1 = entities["Pet"] // nil
let result2 = entities[petVar] // non-nil
let result3 = entities.bridgeToObjectiveC().objectForKey("Pet".bridgeToObjectiveC()) // nil
let result4 = entities.bridgeToObjectiveC().objectForKey(petVar.bridgeToObjectiveC()) // non-nil
// Doesn't Pass
XCTAssertNotNil(NSEntityDescription.entityForName("Pet", inManagedObjectContext: moc));
// Passes
XCTAssertNotNil(NSEntityDescription.entityForName(petVar, inManagedObjectContext: moc));
It works with the key pulled out of the dictionary but not a string that is equivalent to the key (even the hash values are the same).
I think that this pretty definitely shows that there is a bug either in the framework or in Swift itself. I am running Xcode (6b3) and 10.9.4
I think it is time for a bug report.
Related
I'm working on an iOS app using SwiftUI and CoreData and am running into a problem that I cannot seem to figure out.
To provide a little bit of information of what I am trying to do:
I have two CoreData entities that have a One-To-Many relationship:
Tarantula - A tarantula may molt many times (To Many) and when deleted, all of the molts shold also be removed (Cascade)
Molt - A molt belongs to a single Tarantula (To One) and when deleted, should have the reference removed from the Tarantula (Nullify)
I then have a view that lists all of the molts for a given Tarantula that allows adding and deleting molts. It looks like this:
struct MoltListView: View {
private static let DATE_FORMATTER: DateFormatter = {
let d = DateFormatter()
d.dateFormat = "MMM d, y"
return d
}()
#Environment(\.managedObjectContext) private var viewContext
#ObservedObject private var tarantula: Tarantula
#FetchRequest private var molts: FetchedResults<Molt>
#State private var userMessage: String = ""
#State private var displayMessage: Bool = false
init(tarantula: Tarantula) {
self.tarantula = tarantula
self._molts = FetchRequest(entity: Molt.entity(),
sortDescriptors: [NSSortDescriptor(keyPath: \Molt.date, ascending: false)],
predicate: NSPredicate(format: "tarantula = %#", tarantula))
}
var body: some View {
List {
Section(header: Text("Summary")) {
Text("\(molts.count) Molt\(molts.count == 1 ? "" : "s")")
}
Section(header: Text("Molts")) {
NavigationLink(destination: MoltView(tarantula: tarantula, molt: Molt.newModel())) {
Text("Add Molt").foregroundColor(.blue)
}
ForEach(molts, id: \.self) { molt in
NavigationLink(destination: MoltView(tarantula: tarantula, molt: molt)) {
Text(MoltListView.DATE_FORMATTER.string(from: molt.modelDate))
}
}
.onDelete(perform: deleteItems)
}
}.alert(isPresented: $displayMessage) {
Alert(title: Text("Save Failure"), message: Text(userMessage), dismissButton: .default(Text("Ok")))
}
}
private func deleteItems(offsets: IndexSet) {
withAnimation {
offsets.map { molts[$0] }.forEach(viewContext.delete)
do {
try viewContext.save()
} catch {
viewContext.rollback()
userMessage = "\(error): \(error.localizedDescription)"
displayMessage.toggle()
}
}
}
}
The error I am experiencing comes from whenever I try to delete a molt from the list view. The app instantly crashes and the error is:
Simultaneous accesses to 0x7ffb68d2c518, but modification requires exclusive access.
Previous access (a modification) started at SwiftUI`closure #2 in ListCoreCoordinator.tableView(_:commit:forRowAt:) + 53 (0x7fff56544a85).
Current access (a read) started at:
0 libswiftCore.dylib 0x00007fff2f41fe90 swift_beginAccess + 568
1 SwiftUI 0x00007fff56540670 ListCoreCoordinator.dataSource.getter + 50
2 SwiftUI 0x00007fff56541140 ListCoreCoordinator.updateUITableView(_:to:transaction:) + 608
3 SwiftUI 0x00007fff5653ff40 ListRepresentable.updateUIView(_:context:) + 892
4 SwiftUI 0x00007fff569acc60 PlatformViewRepresentableAdaptor.updateViewProvider(_:context:) + 263
5 SwiftUI 0x00007fff565e8ac0 closure #1 in closure #1 in closure #4 in closure #1 in PlatformViewChild.updateValue() + 229
6 SwiftUI 0x00007fff565e89a0 closure #1 in closure #4 in closure #1 in PlatformViewChild.updateValue() + 195
7 SwiftUI 0x00007fff56899b40 ViewRendererHost.performExternalUpdate(_:) + 186
8 SwiftUI 0x00007fff565e8930 closure #4 in closure #1 in PlatformViewChild.updateValue() + 73
9 SwiftUI 0x00007fff565e71e0 closure #1 in PlatformViewChild.updateValue() + 2363
10 SwiftUI 0x00007fff565e6c40 PlatformViewChild.updateValue() + 650
11 SwiftUI 0x00007fff562fa640 partial apply for implicit closure #2 in implicit closure #1 in closure #1 in closure #1 in Attribute.init<A>(_:) + 26
12 AttributeGraph 0x00007fff4be8952a AG::Graph::UpdateStack::update() + 505
13 AttributeGraph 0x00007fff4be89a6a AG::Graph::update_attribute(AG::data::ptr<AG::Node>, bool) + 335
14 AttributeGraph 0x00007fff4be91884 AG::Subgraph::update(unsigned int) + 781
15 SwiftUI 0x00007fff5693a5f0 GraphHost.runTransaction() + 186
16 SwiftUI 0x00007fff5693e110 GraphHost.runTransaction(_:) + 79
17 SwiftUI 0x00007fff5693cba0 GraphHost.flushTransactions() + 211
18 SwiftUI 0x00007fff5693bd40 specialized GraphHost.asyncTransaction<A>(_:mutation:style:) + 464
19 SwiftUI 0x00007fff56509ac0 AttributeInvalidatingSubscriber.invalidateAttribute() + 236
20 SwiftUI 0x00007fff56509a40 AttributeInvalidatingSubscriber.receive(_:) + 105
21 SwiftUI 0x00007fff5650a0d0 protocol witness for Subscriber.receive(_:) in conformance AttributeInvalidatingSubscriber<A> + 16
22 SwiftUI 0x00007fff5669a7e0 SubscriptionLifetime.Connection.receive(_:) + 89
23 Combine 0x00007fff4ab32ec0 ObservableObjectPublisher.Inner.send() + 122
24 Combine 0x00007fff4ab324b0 ObservableObjectPublisher.send() + 801
25 libswiftCoreData.dylib 0x00007fff53ebc900 #objc NSManagedObject._willChange_Swift_Trampoline() + 114
26 CoreData 0x00007fff251b7e4f -[NSManagedObjectContext _postObjectsDidChangeNotificationWithUserInfo:] + 773
27 CoreData 0x00007fff251c6b5b -[NSManagedObjectContext _createAndPostChangeNotification:deletions:updates:refreshes:deferrals:wasMerge:] + 1825
28 CoreData 0x00007fff251b8c0d -[NSManagedObjectContext _processRecentChanges:] + 1041
29 CoreData 0x00007fff2511c241 -[NSManagedObjectContext save:] + 356
30 Tarantulas 0x0000000101a14060 closure #1 in MoltListView.deleteItems(offsets:) + 1165
31 Tarantulas 0x0000000101a07080 thunk for #callee_guaranteed () -> (#error #owned Error) + 15
32 Tarantulas 0x0000000101a16b80 partial apply for thunk for #callee_guaranteed () -> (#error #owned Error) + 20
33 SwiftUI 0x00007fff569b77e0 closure #1 in withTransaction<A>(_:_:) + 83
34 SwiftUI 0x00007fff569b7860 partial apply for closure #1 in withTransaction<A>(_:_:) + 25
35 libswiftCore.dylib 0x00007fff2f22b160 withExtendedLifetime<A, B>(_:_:) + 12
36 SwiftUI 0x00007fff569b7690 withTransaction<A>(_:_:) + 66
37 SwiftUI 0x00007fff569b7580 withAnimation<A>(_:_:) + 140
38 Tarantulas 0x0000000101a13720 MoltListView.deleteItems(offsets:) + 375
39 Tarantulas 0x0000000101a136e0 implicit closure #2 in implicit closure #1 in closure #2 in closure #1 in MoltListView.body.getter + 42
40 SwiftUI 0x00007fff560c0700 partial apply for thunk for #escaping #callee_guaranteed (#in_guaranteed IndexSet) -> () + 17
41 SwiftUI 0x00007fff56713c50 partial apply for thunk for #escaping #callee_guaranteed (#in_guaranteed IndexSet) -> (#out ()) + 17
42 SwiftUI 0x00007fff560c0890 DeleteInteraction.delete() + 125
43 SwiftUI 0x00007fff564a0090 SystemListDataSource.deleteCell(forRowAt:) + 64
44 SwiftUI 0x00007fff56660d40 ShadowListDataSource.commitUpdates() + 963
45 SwiftUI 0x00007fff56544a50 closure #2 in ListCoreCoordinator.tableView(_:commit:forRowAt:) + 76
46 SwiftUI 0x00007fff56544730 ListCoreCoordinator.tableView(_:commit:forRowAt:) + 455
47 SwiftUI 0x00007fff56544ab0 #objc ListCoreCoordinator.tableView(_:commit:forRowAt:) + 131
48 UIKitCore 0x00007fff248ade86 -[UITableView _animateDeletionOfRowAtIndexPath:] + 188
49 UIKitCore 0x00007fff248b68d7 __82-[UITableView _contextualActionForDeletingRowAtIndexPath:usingPresentationValues:]_block_invoke + 60
50 UIKitCore 0x00007fff247fe817 -[UIContextualAction executeHandlerWithView:completionHandler:] + 148
51 UIKitCore 0x00007fff2480c7b4 -[UISwipeOccurrence _executeLifecycleForPerformedAction:sourceView:completionHandler:] + 656
52 UIKitCore 0x00007fff2480cf2d -[UISwipeOccurrence _performSwipeAction:inPullView:swipeInfo:] + 621
53 UIKitCore 0x00007fff2480ec53 -[UISwipeOccurrence swipeActionPullView:tappedAction:] + 92
54 UIKitCore 0x00007fff24816a96 -[UISwipeActionPullView _tappedButton:] + 148
55 UIKitCore 0x00007fff2467b5db -[UIApplication sendAction:to:from:forEvent:] + 83
56 UIKitCore 0x00007fff23fa488d -[UIControl sendAction:to:forEvent:] + 223
57 UIKitCore 0x00007fff23fa4b43 -[UIControl _sendActionsForEvents:withEvent:] + 332
58 UIKitCore 0x00007fff23fa3384 -[UIControl touchesEnded:withEvent:] + 500
59 UIKitCore 0x00007fff241a546a _UIGestureEnvironmentUpdate + 8849
60 UIKitCore 0x00007fff241a4c77 -[UIGestureEnvironment _updateForEvent:window:] + 887
61 UIKitCore 0x00007fff246b893d -[UIWindow sendEvent:] + 4752
62 UIKitCore 0x00007fff2469367d -[UIApplication sendEvent:] + 633
63 UIKitCore 0x00007fff24720d55 __processEventQueue + 13895
64 UIKitCore 0x00007fff2471aca7 __eventFetcherSourceCallback + 104
65 CoreFoundation 0x00007fff2038c369 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
66 CoreFoundation 0x00007fff2038c1be __CFRunLoopDoSource0 + 180
67 CoreFoundation 0x00007fff2038b65c __CFRunLoopDoSources0 + 248
68 CoreFoundation 0x00007fff20385bb1 __CFRunLoopRun + 878
69 CoreFoundation 0x00007fff2038548f CFRunLoopRunSpecific + 567
70 GraphicsServices 0x00007fff2b76ad28 GSEventRunModal + 139
71 UIKitCore 0x00007fff24674df7 -[UIApplication _run] + 912
72 UIKitCore 0x00007fff24679fd3 UIApplicationMain + 101
73 SwiftUI 0x00007fff568cfc60 closure #1 in KitRendererCommon(_:) + 119
74 SwiftUI 0x00007fff568cfbc0 runApp<A>(_:) + 143
75 SwiftUI 0x00007fff56407980 static App.main() + 61
76 Tarantulas 0x0000000101a17940 static TarantulasApp.$main() + 33
77 Tarantulas 0x0000000101a17c20 main + 20
78 libdyld.dylib 0x00007fff20256408 start + 1
The only way I have been able to prevent this error is to remove the delete rule on the Molt->Tarantula relationship from Nullify to No Action. However, this seems more like hack to me instead of a fix.
I was wondering if anyone may have experienced this issue before or may be able to help me in resolving it.
This issue has been confirmed to be due to a system bug.
The workaround is to wrap the delete logic in NSManagedObjectContext.perform. For example:
private func deleteItems(offsets: IndexSet) {
withAnimation {
viewContext.perform { // HERE
offsets.map { molts[$0] }.forEach(viewContext.delete)
do {
try viewContext.save()
} catch {
viewContext.rollback()
userMessage = "\(error): \(error.localizedDescription)"
displayMessage.toggle()
}
}
}
}
For reference, here is the Apple Developer Forum post related to this issue: https://developer.apple.com/forums/thread/668299
I use a NSOutlineView bound to a NSTreeController.
I successfully managed to sort all columns of the view, except one!
This column displays a button that is enabled if the binaryData field is not nil.
The binaryData field in the model is a relationship to a MyBinary NSManagedObject subclass which has a NSData? field. I use this method (a relationship) as recommended to avoid loading all NSData in memory even when not necessary.
I want this column to be sortable, and, when clicked, have all enabled buttons regrouped (ascending or descending order), and all disabled buttons regrouped.
In IB, like other columns, I bound the column value to:
Controller Key = arrangedObjects
Model Key Path = binaryData
But when I click on the column, I have the following stack:
2019-11-09 10:31:44.713177+0100 MyApp[71910:2872832] -[MyApp.MyBinary compare:]: unrecognized selector sent to instance 0x6000021429e0
2019-11-09 10:31:44.713628+0100 MyApp[71910:2872832] [General] -[MyApp.MyBinary compare:]: unrecognized selector sent to instance 0x6000021429e0
2019-11-09 10:31:44.717803+0100 MyApp[71910:2872832] [General] (
0 CoreFoundation 0x00007fff36294f53 __exceptionPreprocess + 250
1 libobjc.A.dylib 0x00007fff6c35a835 objc_exception_throw + 48
2 CoreFoundation 0x00007fff3631f106 -[NSObject(NSObject) __retain_OA] + 0
3 CoreFoundation 0x00007fff3623b6cb ___forwarding___ + 1427
4 CoreFoundation 0x00007fff3623b0a8 _CF_forwarding_prep_0 + 120
5 Foundation 0x00007fff388a1a44 _NSCompareObject + 46
6 CoreFoundation 0x00007fff36206288 __CFSimpleMergeSort + 74
7 CoreFoundation 0x00007fff362061a6 CFSortIndexes + 390
8 CoreFoundation 0x00007fff36223720 CFMergeSortArray + 290
9 Foundation 0x00007fff388a179b _sortedObjectsUsingDescriptors + 592
10 Foundation 0x00007fff388a1397 -[NSArray(NSKeyValueSorting) sortedArrayUsingDescriptors:] + 317
11 AppKit 0x00007fff33666373 -[NSTreeNode sortWithSortDescriptors:recursively:] + 461
12 AppKit 0x00007fff336664be -[NSTreeNode sortWithSortDescriptors:recursively:] + 792
13 AppKit 0x00007fff33666073 -[NSTreeController setSortDescriptors:] + 304
14 Foundation 0x00007fff388e1ce3 -[NSObject(NSKeyValueCoding) setValue:forKey:] + 363
15 AppKit 0x00007fff336695bb -[NSBinder _setValue:forKeyPath:ofObject:mode:validateImmediately:raisesForNotApplicableKeys:error:] + 445
16 AppKit 0x00007fff336693aa -[NSBinder setValue:forBinding:error:] + 236
17 AppKit 0x00007fff33ab0359 -[NSOutlineViewBinder tableView:didChangeToSortDescriptors:] + 119
18 AppKit 0x00007fff337c10cc -[_NSBindingAdaptor tableView:didChangeToSortDescriptors:] + 152
19 AppKit 0x00007fff3366bba8 -[NSTableView setSortDescriptors:] + 258
20 AppKit 0x00007fff33ba44e8 -[NSTableView _changeSortDescriptorsForClickOnColumn:] + 536
21 AppKit 0x00007fff33b8a127 -[NSTableHeaderView _trackAndModifySelectionWithEvent:onColumn:stopOnReorderGesture:] + 999
22 AppKit 0x00007fff33b8d24a -[NSTableHeaderView mouseDown:] + 546
23 AppKit 0x00007fff335f25e9 -[NSWindow(NSEventRouting) _handleMouseDownEvent:isDelayedEvent:] + 4907
24 AppKit 0x00007fff33535eb0 -[NSWindow(NSEventRouting) _reallySendEvent:isDelayedEvent:] + 2612
25 AppKit 0x00007fff3353523d -[NSWindow(NSEventRouting) sendEvent:] + 349
26 AppKit 0x00007fff333f945c -[NSApplication(NSEvent) sendEvent:] + 352
27 AppKit 0x00007fff333e8da7 -[NSApplication run] + 707
28 AppKit 0x00007fff333da95d NSApplicationMain + 777
29 MyApp 0x000000010002b02d main + 13
30 libdyld.dylib 0x00007fff6d6bd2e5 start + 1
31 ??? 0x0000000000000003 0x0 + 3
)
How can I solve this problem? I thought of using Custom Sort Descriptors but I don't exactly know how to tell the OutlineView or the TreeController to use a specific descriptor for a specific column.
Thanks for your help!
how to tell the OutlineView or the TreeController to use a specific descriptor for a specific column
Set sortDescriptorPrototype of the table column.
OK, found it.
The first step was to set a custom NSSortDescriptor on the column using NSTableColumn.sortDescriptorPrototype.
To create the NSSortDescriptor you can use:
init(key: String?, ascending: Bool, comparator: Comparator)
or
init(key: String?, ascending: Bool, selector: Selector?)
which would give for the comparator:
column.sortDescriptorPrototype = NSSortDescriptor(key: "myBindingKeyPath", ascending: true, comparator: { (obj1, obj2) -> ComparisonResult in
// .... your logic
return .orderedSame
})
and for the selector:
Column.sortDescriptorPrototype = NSSortDescriptor(key: "myBindingKeyPath", ascending: true, selector: #selector(MyBinary.compare(_:)))
}
and the compare function in the MyBinary class to be accessed via the selector:
#objc
public func compare(_ other: PDFBinary) -> ComparisonResult {
return .orderedSame
}
The second solution solved my problem, because I was using the autosaveTableColumns property which would cause issue with the first solution.
I'm getting a random error that can't be deterministically recreated, which makes it a pain to debug. The exception is
NSInternalInconsistencyException { Rows: 0x1e5eb080.posErrorMarker == 1 + 1*0x1e5eb080.negError + 1*0x1fa51a40.marker 0x1f933020.negError == 274 + 1*0x1f933020.posErrorMarker + -1*0x1fb84100.marker 0x1fb8d610.negError == 274 + -1
>
0CoreFoundation 0x32c1b3e7 + 162
1libobjc.A.dylib 0x3a916963 objc_exception_throw + 30
2CoreFoundation 0x32c1b307 + 106
3Foundation 0x335ce24f + 190
4Foundation 0x335d0871 + 60
5Foundation 0x335d19e9 + 624
6Foundation 0x335d9eab + 230
7UIKit 0x34e6211b + 162
8UIKit 0x34e67b9f + 26
9CoreFoundation 0x32b61acd CFArrayApplyFunction + 176
10UIKit 0x34e67bdf + 90
11CoreFoundation 0x32b61acd CFArrayApplyFunction + 176
12UIKit 0x34e67bdf + 90
13CoreFoundation 0x32b61acd CFArrayApplyFunction + 176
14UIKit 0x34e67bdf + 90
15CoreFoundation 0x32b61acd CFArrayApplyFunction + 176
16UIKit 0x34e67bdf + 90
17UIKit 0x34e67c6f + 26
18UIKit 0x34a2d769 + 732
19UIKit 0x34a78091 + 72
20UIKit 0x34e3b80d + 132
21UIKit 0x34e48e17 + 1830
22UIKit 0x34e46f37 + 7530
23MyApp 0x00093dd1 __32-[MyController requestStuff:]_block_invoke (MyController.m:123) + 298449
MyController.m:123 is actually just a call to another method method I've defined in MyController.m named requestLocalStuff:
[self requestLocalStuff];
which is strange because it doesn't seem to be throwing the exception on a particular line within requestLocalStuff.
Some context on the how this is being called:
This is on a return from a network call. I am using AFNetworking.
The method making the network call takes a block as a parameter and calls that block after the network call successfully returns; hence the _block_invoke in the stack trace.
requestLocalStuff makes calls to CoreData and eventually updates the UICollectionView in the controller using insertItemsAtIndexPaths. But as the stack trace shows, the error doesn't appear to be thrown from within requestLocalStuff
Due to bugs within UICollectionView, I was forced to subclass UICollectionViewFlowLayout to catch an exception that was crashing the app. Not sure if that can be involved.
My UICollectionViewFlowLayout subclass:
-(void)prepareForCollectionViewUpdates:(NSArray *)updateItems{
#try {
[super prepareForCollectionViewUpdates:updateItems];
}
#catch (NSException *exception) {
DDLogError(#"Error in the layout: %#", exception);
}
#finally {
}
}
I've searched Google for an explanation of posErrorMarker to no avail. Does anyone have a clue of what could be going on here?
I am drawing an signature like this as given below and taking X Y cordinate and saving it to the arry list.
Bitmap bmp;
//Graphics object
Graphics graphics;
//Pen object
Pen pen = new Pen(Color.Black);
// Array List of line segments
ArrayList pVector = new ArrayList();
//Point object
Point lastPoint = new Point(0, 0);
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
// process if currently drawing signature
if (!drawSign)
{
// start collecting points
drawSign = true;
// use current mouse click as the first point
lastPoint.X = e.X;
lastPoint.Y = e.Y;
}
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
// process if drawing signature
if (drawSign)
{
if (graphics != null)
{
// draw the new segment on the memory bitmap
graphics.DrawLine(pen, lastPoint.X, lastPoint.Y, e.X, e.Y);
pVector.Add(lastPoint.X + " " + lastPoint.Y + " " + e.X + " " + e.Y);
// update the current position
lastPoint.X = e.X;
lastPoint.Y = e.Y;
// display the updated bitmap
Invalidate();
}
}
}
Using the arrylist (pVector) I am saving the values to the database as string(singature ) and aslo as image as given below
//Saving value to Database
ArrayList arrSign = new ArrayList();
arrSign = this.signatureControl.getPVector();
string singature = "";
for (int i = 0; i < arrSign.Count; i++)
{
singature = singature + arrSign[i].ToString() + "*";
}
the string singature wiil be like this
60 46 59 48*59 48 59 51*59 51 59 53*59 53 60 49*60 49 61 44*61 44 62 38*62 38 64 31*64 31 67 23*67 23 70 14*70 14 72 10*72 10 75 3*75 3 77 -2*77 -2 76 2*76 2 75 6*75 6 72 17*72 17 71 24*71 24 69 31*69 31 68 46*68 46 67 59*67 59 68 71*68 71 69 79*69 79 70 86*70 86 71 89*71 89 71 93*71 93 71 95*71 95 71 97*71 97 70 95*70 95 69 88*69 88 68 81*68 81 69 77*69 77 69 68*69 68 71 60
//Saving as Image file
Pen pen = new Pen(Color.Black);
string[] arrStr = (signature.Split('*'));
Graphics graphics;
Bitmap bmp = new Bitmap(300, 200);
graphics = Graphics.FromImage(bmp);
graphics.Clear(Color.White);
for (int i = 0; i < arrStr.Length - 2; i++)
{
string[] strArr = new string[4];
strArr = ((arrStr[i].ToString()).Split(' '));
graphics.DrawLine(pen, Convert.ToInt32(strArr[0].ToString()), Convert.ToInt32(strArr[1].ToString()),
Convert.ToInt32(strArr[2].ToString()), Convert.ToInt32(strArr[3].ToString()));
}
string pathToCopyImage = systemBus.TempFile;
bmp.Save(pathToCopyImage + "\\" + dsReportDetails.Tables["tblDelivery"].Rows[0]["PKDelivery"].ToString() + "_Signature.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
bmp.Dispose();
My problem is that after Saving the signature as Image file I am not able to convert it back to arrylist like the one that i am used to save the value in the database.
ie I need to convert the image file back to as given below format
60 46 59 48*59 48 59 51*59 51 59 53*59 53 60 49*60 49 61 44*61 44 62 38*62 38 64 31*64 31 67 23*67 23 70 14*70 14 72 10*72 10 75 3*75 3 77 -2*77 -2 76 2*76 2 75 6*75 6 72 17*72 17 71 24*71 24 69 31*69 31 68 46*68 46 67 59*67 59 68 71*68 71 69 79*69 79 70 86*70 86 71 89*71 89 71 93*71 93 71 95*71 95 71 97*71 97 70 95*70 95 69 88*69 88 68 81*68 81 69 77*69 77 69 68*69 68 71 60
Will any one help me please
It is not very easy to get your "signature string" back from image so you can just add you "string signature" to saved image as a metadata tag of image (as a Description for example). So then you read your image back you don't need to recognize "signature string" from image, you can just read it from metadata as a string. Msdn has a nice article about image metadata and api to work with them. http://msdn.microsoft.com/en-us/library/ms748873.aspx
By the way, your code for concatenating "signature string" is slow and memory consuming. It is better to use StringBuilder in such situations in .Net. And overall strings are not the best data structure to store list of points. But it depends on requirements for your app.
I'm trying to fetch from Core Data records that have a startTime between two dates.
Here's my code:
NSDate *today = [NSDate date];
NSDate *distantFuture = [NSDate distantFuture];
// Create the predicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"startTime BETWEEN %#", [NSArray arrayWithObjects:today, distantFuture, nil]];
NSLog(#"today: %#, distantFuture: %#", today, distantFuture);
NSLog(#"predicate: %#", predicate);
// Add the predicate to the fetchRequest
[[[self fetchedResultsController] fetchRequest] setPredicate:predicate];
NSError *error;
if (![[self fetchedResultsController] performFetch:&error])
{
// Update to handle the error appropriately.
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
exit(-1); // Fail
}
And here's the console output:
2011-03-11 02:00:03.166 TestApp[2668:307] today: 2011-03-11 01:00:03 AM +0000, distantFuture: 4001-01-01 12:00:00 AM +0000
2011-03-11 02:00:03.174 TestApp[2668:307] predicate: startTime BETWEEN {2011-03-11 01:00:03 AM +0000, 4001-01-01 12:00:00 AM +0000}
2011-03-11 02:00:03.180 TestApp[2668:307] -[__NSDate constantValue]: unrecognized selector sent to instance 0x1e7ff0
2011-03-11 02:00:03.198 TestApp[2668:307] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSDate constantValue]: unrecognized selector sent to instance 0x1e7ff0'
*** Call stack at first throw:
(
0 CoreFoundation 0x314d0987 __exceptionPreprocess + 114
1 libobjc.A.dylib 0x319a149d objc_exception_throw + 24
2 CoreFoundation 0x314d2133 -[NSObject(NSObject) doesNotRecognizeSelector:] + 102
3 CoreFoundation 0x31479aa9 ___forwarding___ + 508
4 CoreFoundation 0x31479860 _CF_forwarding_prep_0 + 48
5 CoreData 0x352ed973 -[NSSQLSimpleWhereIntermediate _generateSQLBetweenStringInContext:] + 766
6 CoreData 0x35244fff -[NSSQLSimpleWhereIntermediate generateSQLStringInContext:] + 502
7 CoreData 0x35244647 -[NSSQLFetchIntermediate generateSQLStringInContext:] + 74
8 CoreData 0x352e42b3 -[NSSQLGenerator newSQLStatementForFetchRequest:ignoreInheritance:countOnly:nestingLevel:] + 234
9 CoreData 0x352414ab -[NSSQLAdapter _newSelectStatementWithFetchRequest:ignoreInheritance:] + 378
10 CoreData 0x35241329 -[NSSQLAdapter newSelectStatementWithFetchRequest:] + 16
11 CoreData 0x35241205 -[NSSQLCore newRowsForFetchPlan:] + 288
12 CoreData 0x35240531 -[NSSQLCore objectsForFetchRequest:inContext:] + 420
13 CoreData 0x35240151 -[NSSQLCore executeRequest:withContext:error:] + 304
14 CoreData 0x352d0295 -[NSPersistentStoreCoordinator executeRequest:withContext:error:] + 896
15 CoreData 0x3523d877 -[NSManagedObjectContext executeFetchRequest:error:] + 374
16 CoreData 0x352f541b -[NSFetchedResultsController performFetch:] + 766
17 TestApp 0x0001ac6d -[MatchesCalendarDataSource loadMatchesFrom:to:delegate:] + 268
18 TestApp 0x0001ad51 -[MatchesCalendarDataSource presentingDatesFrom:to:delegate:] + 68
19 TestApp 0x00021353 -[KalViewController reloadData] + 110
20 TestApp 0x00021b15 -[KalViewController loadView] + 452
21 UIKit 0x338dc227 -[UIViewController view] + 30
22 UIKit 0x338e8d0b -[UIViewController contentScrollView] + 22
23 UIKit 0x338e8b7b -[UINavigationController _computeAndApplyScrollContentInsetDeltaForViewController:] + 30
24 UIKit 0x338e8a79 -[UINavigationController _layoutViewController:] + 24
25 UIKit 0x338e84d3 -[UINavigationController _startTransition:fromViewController:toViewController:] + 254
26 UIKit 0x338e835f -[UINavigationController _startDeferredTransitionIfNeeded] + 182
27 UIKit 0x338e82a3 -[UINavigationController viewWillLayoutSubviews] + 14
28 UIKit 0x338e823f -[UILayoutContainerView layoutSubviews] + 138
29 UIKit 0x338b10cf -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 26
30 CoreFoundation 0x3146ebbf -[NSObject(NSObject) performSelector:withObject:] + 22
31 QuartzCore 0x30a6c685 -[CALayer layoutSublayers] + 120
32 QuartzCore 0x30a6c43d CALayerLayoutIfNeeded + 184
33 QuartzCore 0x30a6656d _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 212
34 QuartzCore 0x30a66383 _ZN2CA11Transaction6commitEv + 190
35 QuartzCore 0x30a89f9d _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 52
36 CoreFoundation 0x31460c59 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 16
37 CoreFoundation 0x31460acd __CFRunLoopDoObservers + 412
38 CoreFoundation 0x314580cb __CFRunLoopRun + 854
39 CoreFoundation 0x31457c87 CFRunLoopRunSpecific + 230
40 CoreFoundation 0x31457b8f CFRunLoopRunInMode + 58
41 GraphicsServices 0x35d664ab GSEventRunModal + 114
42 GraphicsServices 0x35d66557 GSEventRun + 62
43 UIKit 0x338d5329 -[UIApplication _run] + 412
44 UIKit 0x338d2e93 UIApplicationMain + 670
45 TestApp 0x000029d7 main + 70
46 TestApp 0x00002958 start + 52
)
terminate called after throwing an instance of 'NSException'
I've also tried the predicate below, which uses >= AND <= instead of the BETWEEN statement (see below). This doesn't cause an error but neither does it fetch any records!
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(startTime >= %#) AND (startTime <= %#)", today, distantFuture];
As a test I've tried a predicate that doesn't include NSDate objects and it works fine (see below):
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"location.title == %#", #"Boston"];
Any help or advice would be much appreciated.
Many thanks, Matthew
Edit
Thanks for your help Dave.
So now I'm back to using the <= construct but I'm getting 0 objects fetched.
I was just using today and distantFuture as a test to make absolutely sure that my startTime would be between those dates. In the real code it's a range from fromDate to toDate.
Here's my NSPredicate:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"( ( %# <= %K ) && ( %K <= %# ) )", fromDate, #"startTime", #"startTime", toDate];
Here's the console output:
predicate: CAST(336261600.000000, "NSDate") <= startTime AND startTime <= CAST(339285599.000000, "NSDate")
[sectionInfo numberOfObjects]: 0
Here are the dates that are in Core Data (the Attribute Type is set to Date):
startTime
---------
337249800
337309200
337318200
I have no idea why 0 objects are returned. Can anyone see where I'm going wrong?
According to the documentation, the BETWEEN operator counts as an aggregate expression, and ...
Aggregate expressions are not supported by Core Data.
So yes, in order to work around this, you must use the >= and <= construction.
However, given that one of your dates is [NSDate distantFuture], you don't need the "less than" comparison at all. You should be able to do:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"startTime >= %#", [NSDate date]];
Perhaps try using AND instead of && (although your console output seems to show it converting correctly.
I just posted an example that works for me, note that my condition is flipped like so:
#"(%K >= %#) AND (%K <= %#)"
Here is the full example