UISplitViewController Swipe On Detail Navigate Back And Forth - ios

Starting with the default SplitViewController project I added a swipe left and right gesture to the detail view. I defined a protocol that the master view implements when a swipe left or right occurs.
protocol SwipeDelegate: AnyObject {
func onSwippedLeft()
func onSwippedRight()
}
In the MasterViewController the onSwippedLeft() implementation advances the currently selected item by one:
func onSwippedLeft() {
let currentRow = self.tableView.indexPathForSelectedRow?.row
if currentRow == objects.count - 1 {
print("Already on first item")
return
}
let newIndexPath = IndexPath(row: currentRow! + 1, section: 0)
self.tableView!.selectRow(at: newIndexPath, animated: true, scrollPosition: UITableView.ScrollPosition.middle)
self.tableView(self.tableView, didSelectRowAt: newIndexPath)
}
The problem occurs when I add the last line. Visually everything works; as I swipe left I see the selection on the tableview move forward; however, the last line I'm attempting to manually perform a selection so that as the selected item advances the detail view is replaced with contents for that item.
[MasterDetailDefault.MasterViewController tableView:didSelectRowAtIndexPath:]: unrecognized selector sent to instance 0x7fabe28084e0
2018-09-19 09:07:11.618683-0700 MasterDetailDefault[87530:2282523] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[MasterDetailDefault.MasterViewController tableView:didSelectRowAtIndexPath:]: unrecognized selector sent to instance 0x7fabe28084e0'
*** First throw call stack:
(
0 CoreFoundation 0x000000011075929b __exceptionPreprocess + 331
1 libobjc.A.dylib 0x000000010fcf5735 objc_exception_throw + 48
2 CoreFoundation 0x0000000110777fa4 -[NSObject(NSObject) doesNotRecognizeSelector:] + 132
3 UIKitCore 0x0000000113e9b163 -[UIResponder doesNotRecognizeSelector:] + 287
4 CoreFoundation 0x000000011075dd14 ___forwarding___ + 772
5 CoreFoundation 0x000000011075fe88 _CF_forwarding_prep_0 + 120
6 MasterDetailDefault 0x000000010f3c2971 $S19MasterDetailDefault0A14ViewControllerC13onSwippedLeftyyF + 2321
7 MasterDetailDefault 0x000000010f3c331e $S19MasterDetailDefault0A14ViewControllerCAA13SwipeDelegateA2aDP13onSwippedLeftyyFTW + 30
What is my error here?
UPDATE 1
I ran the code today without haven't touched anything and this crash no longer happens. I removed the last line as suggested:
self.tableView(self.tableView, didSelectRowAt: newIndexPath)
and replaced it with firing the segue manually:
self.performSegue(withIdentifier: "showDetail", sender: nil)
Now here is the weird part. On iPad everything works as expected now, in any orientation, but not on iPhone. On iPad when I swipe it just replaces the details view with one that contains the new data. On iOS it pushes, without replacing, a new detail controller.
I don't understand how the same code running on the same OS has this odd behavior. I'm assuming it's a bug that will require some kind of workaround. Any suggestions?

Related

NSTableView binding + delegate causes array index error

I have a view-based NSTableView which uses bindings to an NSArrayController.
As soon as I add a delegate to the table view, I start getting:
Ignoring exception raised in void run_cocoa_block(void *): *** -[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array
and
MyApp[59144:25384659] *** -[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array
MyApp[59144:25384659] (
0 CoreFoundation 0x00007fff93410452 __exceptionPreprocess + 178
1 libobjc.A.dylib 0x00007fff9601af7e objc_exception_throw + 48
2 CoreFoundation 0x00007fff93327775 -[__NSArrayM objectAtIndex:] + 245
3 AppKit 0x00007fff9bd7ad31 -[NSTableRowData _addViewToRowView:atColumn:row:] + 535
4 AppKit 0x00007fff9bd7a98e -[NSTableRowData _addViewsToRowView:atRow:] + 184
5 AppKit 0x00007fff9bd791a7 -[NSTableRowData _initializeRowView:atRow:] + 390
6 AppKit 0x00007fff9bd77907 -[NSTableRowData _addRowViewForVisibleRow:withPriorView:] + 416
If I remove the delegate connection, everything works fine... the table fills properly from the NSArrayController that it is bound to, and the cells/columns get the correct data as well.
I need the delegate to use
-(BOOL)control:(NSControl *)control textShouldEndEditing:(NSText *)fieldEditor
What might be causing this?
Elsewhere in the app, I have a sheet that also uses a view-based NSTableView with bindings and it works fine with a delegate.
In awakeFromNib:, I was calling:
[[self itemsController] setContent:[[[NSMutableArray alloc] init] autorelease]];
this worked in a cell-based NSTableView but not in a view-based one. I'm not sure why, but giving it this empty array may have been happening after the binding took place but before the OS did something else with it and the empty array was confusing it.

Irregular crash when creating NSManagedObject out of NSSet

I have an irregular crash (1 in 5 times on devices, 4 in 5 times on Simulator). I have set an exception breakpoint and it occurs on the following line without any console information:
if let carColorSet = car.carToDisplay?.allObjects as? [Display] {
Note: car.carToDisplay is an NSSet
Before I set the exception breakpoint, I would get the following info in the console when it crashed:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSMutableSet unionSet:]: set argument is not an NSSet'
*** First throw call stack:
(
0 CoreFoundation 0x0000000102e79b0b __exceptionPreprocess + 171
1 libobjc.A.dylib 0x00000001023d6141 objc_exception_throw + 48
2 CoreFoundation 0x0000000102e00051 -[NSMutableSet unionSet:] + 1041
3 CoreData 0x0000000101b10df8 -[_NSFaultingMutableSet willReadWithContents:] + 936
4 CoreData 0x0000000101af131b -[_NSFaultingMutableSet allObjects] + 27
5 Keyboard 0x00000001018f838e
Any idea here? It seems like the crash occurs when I try to turn that carToDisplay?.allObjects into an array of Display objects.
This is a keyboard extension app btw.
Thank you for any input!
Problem (probably):
if let carColorSet = car.carToDisplay?.allObjects as? [Display]
carToDisplay is a NSet
However the function allObjects returns an array
I think you are trying to do a unionSet with an array.
Update the Question:
Please update your question, the qestion doesn't state the correct line of error.
The question needs to do the following
state where the unionSet is invoked.
what the argument type of unionSet is.

Could Not load Nib in bundle

I have not been able to upload a Nib to my table view, this problem happened with other application I was working on as well, even though I did have some NIb's files working just fine. I have even reinstall Xcode trying to fix the problem. I am register my Nib as follows
let test = "test"
let cellNib = UINib(nibName: test, bundle: nil)
tableView.register(cellNib, forCellReuseIdentifier: test)
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: test, for:indexPath) as! testCell //after this function is called I get a crash
return cell
}
This is part of the message I get from the crash, I do not know if is useful.
'NSInternalInconsistencyException', reason: 'Could not load NIB in bundle: 'NSBundle (loaded)' with name 'tests''
*** First throw call stack:
(
0 CoreFoundation 0x000000010afdab0b __exceptionPreprocess + 171
1 libobjc.A.dylib 0x0000000107b98141 objc_exception_throw + 48
2 CoreFoundation 0x000000010b043625 +[NSException raise:format:] + 197
3 UIKit 0x0000000108b59b24 -[UINib instantiateWithOwner:options:] + 501
4 UIKit 0x00000001088ac567 -[UITableView _dequeueReusableViewOfType:withIdentifier:] + 402
5 UIKit 0x00000001088aca4b -[UITableView dequeueReusableCellWithIdentifier:forIndexPath:] + 71
6 Chaol 0x000000010759ebe9 _TFC5Chaol23QuestionsViewController9tableViewfTCSo11UITableView12cellForRowAtV10Foundation9IndexPath_CSo15UITableViewCell + 153
My .XIB file appears on copy bundle resources.
Perhaps the nib file is not added to your target.
Try those steps:
In Project > Target > Build Phases
expand Copy Bundle Resources
click + button and add the required NIB file.
Clean your build by Shift+Cmd+K, then run.
In your .xib file
click on File Inspector
in Target Membership section, select the target you are using
Also, double check the spelling of your nib name.

*** Terminating app due to uncaught exception 'NSGenericException', reason: 'Start date cannot be later in time than end date!'

I am using Alamofire and after several hours of my app running on the simulator I got a crash with this error.
*** Terminating app due to uncaught exception 'NSGenericException', reason: 'Start date cannot be later in time than end date!'
I got this stack trace in console:
*** First throw call stack:
(
0 CoreFoundation 0x0000000111186d4b __exceptionPreprocess + 171
1 libobjc.A.dylib 0x0000000110be821e objc_exception_throw + 48
2 Foundation 0x00000001107f0e3c -[_NSConcreteDateInterval dealloc] + 0
3 CFNetwork 0x00000001131a18e8 -[__NSCFURLSessionTaskMetrics _initWithTask:] + 868
4 CFNetwork 0x00000001131a1497 -[NSURLSessionTaskMetrics _initWithTask:] + 100
5 CFNetwork 0x0000000112f77bc7 -[__NSCFURLLocalSessionConnection _tick_finishing] + 351
6 libdispatch.dylib 0x00000001128e3978 _dispatch_call_block_and_release + 12
7 libdispatch.dylib 0x000000011290d0cd _dispatch_client_callout + 8
8 libdispatch.dylib 0x00000001128eae17 _dispatch_queue_serial_drain + 236
9 libdispatch.dylib 0x00000001128ebb4b _dispatch_queue_invoke + 1073
10 libdispatch.dylib 0x00000001128ee385 _dispatch_root_queue_drain + 720
11 libdispatch.dylib 0x00000001128ee059 _dispatch_worker_thread3 + 123
12 libsystem_pthread.dylib 0x0000000112cbc736 _pthread_wqthread + 1299
13 libsystem_pthread.dylib 0x0000000112cbc211 start_wqthread + 13
)
libc++abi.dylib: terminating with uncaught exception of type NSException
Did someone get the similar crash?
Thanks
I had the same crash and did some research today and found this:
http://www.openradar.me/28301343
It looks Apple fixed the issue in iOS 10.2. just thought it may help you!
Yes I just got the same exact crash. It happened in a background thread and it seems to have to do with making a URL session network request. I wonder if it's some sort of multithreading bug having to do with the fact that I'm making two network requests at the same time. I'm using Alamofire as well but not sure if the bug lies in Alamofire or in Apple's code. I've been unable to reproduce it as of now. Maybe you can figure out how to reproduce it and then file an issue in Apple's bug radar or in the Alamofire GitHub repo.
This is a bug in Apple's NSURLSessionTaskMetrics code and happens during a network request when the user's clock gets moved far enough backwards that the request start timestamp is after the request end timestamp. This is reproducible using a network debugging proxy and manually adjusting the clock, and only occurs from iOS 10.0 up to but not including iOS 10.2
If you're using Alamofire, and you don't need NSURLSessionTaskMetrics, you can work around this by using a custom SessionDelegate for your SessionManager and overriding the responds(to aSelector..) function e.g:
class MySessionDelegate: Alamofire.SessionDelegate {
override public func responds(to aSelector: Selector) -> Bool {
let result: Bool = super.responds(to: aSelector)
if #available(iOS 10.2, *) {
// NSURLSessionTaskMetrics date crash is fixed
return result
} else if #available(iOS 10.0, *) {
// NSURLSessionTaskMetrics date crash is not fixed, turn off metric collection
if aSelector == #selector(self.urlSession(_:task:didFinishCollecting:)) {
return false
} else {
return result
}
} else {
// NSURLSessionTaskMetrics doesn't exist
return result
}
}
}
If you're using the default SessionManager (e.g. calling Alamofire.request(...)) you can create your own SessionManager instead in order to use your custom SessionDelegate:
let sessionManager: Alamofire.SessionManager = {
let configuration: URLSessionConfiguration = URLSessionConfiguration.default
configuration.httpAdditionalHeaders = SessionManager.defaultHTTPHeaders
return Alamofire.SessionManager(configuration: configuration, delegate: MySessionDelegate(), serverTrustPolicyManager: nil)
}()
And now instead of calling Alamofire.request(...) you'd call sessionManager.request(...)
I have been struggling with this problem in an os x application for the last few months and have found a workaround.
Background:
Like the OP am using Alamofire to request JSON data via a Timer to send requests several times per second. The data comes in as expected however I get random crashes at irregular intervals with the same message as the OP i.e. Start date cannot be later in time than end date! etc etc.
Solution:
Rather than send Alamofire requests at a regular interval I added some logic which checks for a return of the previous request before sending the next one. This completely eliminated the random crashes.
Hope it helps :)
#thierryb

tableView crashes on end up with more than 16 items

This is very confusing.
I have a UITableView, which updates and works fine until it gets more than 16 items then it crashes when trying to endUpdates after calling insertRowsAtIndexPaths.
The NSIndexPaths being added are all valid. -numberOfRowsInSection returns the correct number. It is not throwing an error related to the data set, rather it crashes with
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
when endUpdates is called on the tableView.
The data source is all there, the NSIndexPaths are fine. the code works fine between 0 and 16 rows, but when I add a 17th it crashes. Additionally if I start it with 22 items it works fine, when I add the 23rd it crashes... if I call reload data instead of doing the update and insert process it works fine, so it's nothing to do with the data itself, and it shouldn't be anything to do with how I'm inserting the rows since it works through 16...
I'm completely perplexed. Here is my update method. It is being called on the main thread at all times.
- (void)updateConversation:(NSNotification*)notification
{
NSDictionary *updateInfo = [notification userInfo];
//NSLog(#"Got update %#", updateInfo);
if ([[updateInfo objectForKey:#"success"] integerValue] == YES) {
[self updateConversationUI];
int addedStatementCount = [[updateInfo objectForKey:#"addedStatementCount"] intValue];
if (addedStatementCount > 0) {
//[self.tableView reloadData];
[self.tableView beginUpdates];
int previousStatmentCount = [[updateInfo objectForKey:#"previousStatmentCount"] intValue];
NSLog(#"owner %i, Was %i, now %i, change of %i", self.owner, previousStatmentCount, (int)self.conversation.statements.count, addedStatementCount);
NSMutableArray *rowPaths = [[NSMutableArray alloc] init];
for (int i = previousStatmentCount; i < previousStatmentCount + addedStatementCount; i++) {
NSIndexPath *path = [NSIndexPath indexPathForRow:i inSection:0];
[rowPaths addObject:path];
}
[self.tableView insertRowsAtIndexPaths:rowPaths withRowAnimation:UITableViewRowAnimationBottom];
[self.tableView endUpdates];
[self.tableView scrollToRowAtIndexPath:[rowPaths lastObject] atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
}
}
The rest of the crash past [self.tableView endUpdates] is UITableView
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
*** First throw call stack:
(
0 CoreFoundation 0x000000010189b795 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x00000001015fe991 objc_exception_throw + 43
2 CoreFoundation 0x0000000101852564 -[__NSArrayM insertObject:atIndex:] + 820
3 UIKit 0x0000000100317900 __46-[UITableView _updateWithItems:updateSupport:]_block_invoke691 + 173
4 UIKit 0x00000001002b5daf +[UIView(UIViewAnimationWithBlocks) _setupAnimationWithDuration:delay:view:options:factory:animations:start:animationStateGenerator:completion:] + 460
5 UIKit 0x00000001002b6004 +[UIView(UIViewAnimationWithBlocks) animateWithDuration:delay:options:animations:completion:] + 57
6 UIKit 0x00000001003174cb -[UITableView _updateWithItems:updateSupport:] + 2632
7 UIKit 0x0000000100312b18 -[UITableView _endCellAnimationsWithContext:] + 11615
8 Dev App 0x0000000100006036 -[ConversationViewController updateConversation:] + 998
9 CoreFoundation 0x00000001018f121c __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12
10 CoreFoundation 0x000000010185370d _CFXNotificationPost + 2381
11 Dev App 0x00000001000055ac -[ConversationManager postNotification:] + 92
12 Foundation 0x0000000101204557 __NSThreadPerformPerform + 227
13 CoreFoundation 0x000000010182aec1 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
14 CoreFoundation 0x000000010182a792 __CFRunLoopDoSources0 + 242
15 CoreFoundation 0x000000010184661f __CFRunLoopRun + 767
16 CoreFoundation 0x0000000101845f33 CFRunLoopRunSpecific + 467
17 GraphicsServices 0x00000001039a23a0 GSEventRunModal + 161
18 UIKit 0x0000000100261043 UIApplicationMain + 1010
19 Dev App 0x0000000100003613 main + 115
20 libdyld.dylib 0x0000000101f2a5fd start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
This seems like a bug in the OS, the stack would indicate that it's something to do with the animation block but it happens no matter what I set the animation to, including none.
And to re-state. This works through 16 items, then inserting items past that causes a crash. It is also called at initial setup to load data, and it will load any number of items there, including well over 16. But when called again, purely as an update from 16 or more to something higher it will crash.
Most bizarre issue I've yet to encounter with table views...
under iOS 7 on device and simulator, latest Xcode for reference.
It seems that the problem is caused by my call of scrollToRowAtIndexPath (even though it crashes before it gets there...) combined with implementing tableView:estimatedHeightForRowAtIndexPath: by removing the row height estimate the crash went away... still seems like a bug in the animation system for tables to me. Thankfully I don't need the estimated row height, I had forgotten I had implemented it (trying to play nice by iOS 7 bites me again).
Place strategic breakpoints when you are incrementing the statement count, go through the loop of adding the rows as many times as you need to, and locate the statement that it's causing the crash, at that moment take a look at your objects and look for nil values as the error you are having it's trying to insert a nil object(or un-existent) from an Array.
I would personally recommend you to go through this loop entirely while keeping an exe for the path and previous statement count .
NSIndexPath *path = [NSIndexPath indexPathForRow:i inSection:0];
in my case the tableView:heightForHeaderInSection: method has been missing,
hadn't implemented the tableView:estimatedHeightForRowAtIndexPath method so this also could be solving the problem if you aren't using tableView:estimatedHeightForRowAtIndexPath:
Your problem is that you don't update the dataSource the tableView is using.
if you insert a row, you need to insert the appropriate object to the array the tableView is using.
Goodluck!

Resources