How to debug inside performBatchUpdates - ios

I append objects in the collectionView model inside performBatchUpdates, something like that :
collectionView.performBatchUpdates({
for item in items{
// Append the different objects... example:
if item is Picture{
self.modelCollection.append(item, cellReuseIdentifier: "Picture")
}
}
}, completion: { completed in
self.isRefreshing = false
I am sorry but I can't post the original code. This code is inside a function called after the data is reloaded or when the device orientation changes to rearrange the collectionView cells. When the device is reloading the data and the orientation change at the same time I get an error
Terminating app due to uncaught exception
'NSInternalInconsistencyException', reason: 'request for index path
for global index 536870881 when there are only 31 items in the
collection view'
I know it's not easy to understand the problem without the complete code but my problem consist on how to debug this error? I am almost sure that the problem is inside performBatchUpdates.I put a beakpoint in every single line but I get the error only in the completion closure without any other informations. Do you have an idea on what is going on or how to debug this ?

Related

SwiftUI: app crashed with "UITableView internal inconsistency" error

Update: After spending several hours doing experiment, I finally identify the root cause. See this. I'll close the question.
My app crashed with "UITableView internal inconsistency" error in a random manual testing. Below is the error message (I removed the stack trace because it's long).
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UITableView internal inconsistency: encountered out of bounds global row index while preparing batch updates (oldRow=2, oldGlobalRowCount=2)'
The error usually occurs in UIKit apps. In my SwiftUI app, however, I don't deal with UIKit directly, it's SwiftUI that does it. So my first thought was that this was a bug in SwiftUI. But this is a very basic error (it was an "out of index" error). That, plus the fact it occurred after I made a minor change to the app, makes me not sure. I wonder if anyone saw this issue in your app? Could it be caused by the an incorrect way of doing SwiftUI programming?
More information:
This was first time I observed the crash. I observed it more than once since then but couldn't reproduce it consistently, not to mention provide a simple example to demonstrate it.
I first observed the crash after I made a minor change to my app (though I'm not sure if the change is relevant). The purpose of the change it to generalize the code to implement a custom binding. In the old code, the custom binding reads/writes data by capturing data in closure. In the new code, the custom binding reads/writes data through another binding (could the use of that additional binding cause the issue?). The text field is in a form. The crash occurred when I clicked save button in the form.
Old code:
#ObservedObject var param: Param
...
TextField("Notes", text: Binding(
get: { param.notes ?? "" },
set: { param.note = ($0 != "" ? $0 : nil) } ))
New code:
func nonOptionalText(_ value: Binding<String?>) -> Binding<String> {
return Binding() {
value.wrappedValue ?? ""
} set: { newValue in
value.wrappedValue = (newValue != "" ? newValue : nil)
}
}
...
#ObservedObject var param: Param
...
TextField("Notes", text: nonOptionalText($param.notes))

Firebase crashes with 'listen() called twice for the same query' error

I was trying to follow the advice and remove the listener when needed and register the listener when needed. So in my UIViewController.viewDidAppear I have the following:
let chatRef = messagesRef.childByAppendingPath(chat.objectId!)
var query = chatRef.queryOrderedByChild("createdAt")
if let since = since {
query = query.queryStartingAtValue(since.timeIntervalSince1970 * 1000)
}
let handle = query.observeEventType(FEventType.ChildAdded, withBlock: completion, withCancelBlock: { (error: NSError!) -> Void in
println("error listening for new Chat messages: \(error)")
});
In my UIViewController.viewWillDisappear() I have
let chatRef = messagesRef.childByAppendingPath(chat.objectId!)
if chatRef != nil {
chatRef.removeAllObservers()
}
But the program crashes every time the ViewController is entered the second time (going to the view controller, navigate away, then come back) with the following error:
*** Assertion failure in -[FPersistentConnection listen:tagId:hashFn:onComplete:], /Users/mtse/Dev/firebase/firebase-client-objc/Firebase/Firebase/Core/FPersistentConnection.m:127
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'listen() called twice for the same query'
The program runs fine if I don't remove the observers and call observeEventType only once in viewDidLoad instead of viewDidAppear.
The program also runs fine even if I remove the observer then add it back if I don't do queryOrderedByChild and queryStartingAtValue.
So what am I doing wrong here?
Disclaimer: I work for Firebase
Listeners in Firebase are specific to the path or query that you register them on. Calling removeAllObservers() removes all observers, but only from that path.
So in your viewWillDisappear() you will need to remove the listeners from the query, instead of the ref.
query.removeAllObservers()
We just made this more explicit in our documentation and are looking at ways to make the API more intuitive.
Update (20150724)
It turns out that calling removeAllObservers() on a FFirebase should remove all observers on queries on that same location too. It will not remove observers at child() locations, but should have worked in your case.
We are investigating what is going wrong, but it seems you have hit a bug in our iOS SDK. Once we find it, we'll release a fixed version. In the meantime the above serves (and will continue to serve) as a valid workaround.

Assertion failure in -[NSIndexPath row] with AppList dataSource

See update below.
I'm writing a tweak and am using AppList. I am hooking into spotlight and creating a table off all installed applications. I am trying to use the dataSource to get the information (display identifier etc). The problem is if dataSource is defined... I get the following error:
SpringBoard[1622] <Warning>: *** Assertion failure in -[NSIndexPath row], /SourceCache/UIKit/UIKit-2380.17/UITableViewSupport.m:2680
SpringBoard[1622] <Warning>: ***** AltKeyboard Uncaught Exception: Invalid index path for use with UITableView. Index paths passed to table view must contain exactly two indices specifying the section and row. Please use the category on NSIndexPath in UITableView.h if possible. *****
or
SpringBoard[1890] <Warning>: ***** AltKeyboard Uncaught Exception: *** -[__NSArrayM objectAtIndex:]: index 2 beyond bounds [0 .. 1] *****
SpringBoard[1890] <Error>: *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 2 beyond bounds [0 .. 1]'
*** First throw call stack:
If dataSource is not defined and I use fake data (test name), the table is generated fine. When I print the dataSource there are only two items in it.
Ryan Petrich, on IRC, seemed to suggest that I was doing everything completely wrong but wasn't much help after that. Perhaps I am going about solving this problem incorrectly?
Code: http://pastebin.ca/2457626
Repository: https://github.com/twodayslate/ListLauncher
edit/update!
dataSource is giving me problems. It isn't fetching the same number of apps and thus I am getting index errors and the like. I have over 200 apps but dataSource is only fetching 2.
The following code gives no errors but only displays 2 items: http://pastebin.ca/2458961
edit!
I changed it so I just use ALApplicationList. I am able to get all the applications listed. However, when I attempt to scroll through the table, it crashes. Sorting and creating the list is really slow so I believe that might be causing the problem. I'm no pro at obj-c so I'm sure there is a better way than what I am doing. http://pastebin.ca/2459318
Your problem is twofold. First, UITableView expects to be handed index paths containing both a row and a section, where you've provided it with only a row. Second, you cannot expect unchecked array access to succeed 100% of the time, so bounds check whatever access calls you might be using. It also wouldn't hurt to use some retains in the iVar assignments you've got in your code unless you don't need to hold a reference to it (but it looks like you do).
I figured out an alternative solution to ALDataSource. I sorted ALApplicationList.applications. The problem was that the instance of the sorted NSArray would keep disappearing. So I did [values retain] and everything worked! Reinitializing the sorted values was too slow and would crash the device.
Here is the working code that successfully lists all the apps: http://pastebin.ca/2459778

Zero object in array crashes the program, also after certain count

I have a program that grabs data from Instagram, puts it into dictionary and then I parse it.
Problems begin when I try to use that data, magically item number 0 crashes my program.
Also, after certain number next item also crashes the program.
Here is the code for UITableViewCell, that grabs text from the array/dictionaries and puts it into cell. As it looks, it crashes, if I add another check to start with number 1, it works, but crashes later when it reaches some count.
I don't understand why this happens, since I have the method that tells the TableView how many rows are in table, and it returns [self.loader.dataArray count], so it can't possibly try to load the thing that is out of bounds.
if (self.loader.dataArray[indexPath.row] != nil )
{
cell.textLabel.text = [[[self.loader.dataArray[indexPath.row] objectForKey:#"caption"] objectForKey:#"from"] objectForKey:#"full_name"];
}
Here is the error I am getting:
instagramClient[8254:907] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSNull objectForKey:]: unrecognized selector sent to instance 0x3bb8f090'
The exception that you're getting does not indicate an out of bounds issue, it indicates that you have got an NSNull in your dataArray (or possibly in the "caption" object of one of the dictionaries in your dataArray or in the "from" object of one of those dictionaries, and so on). Try logging all of self.loader.dataArray when you get updates to that array and see if it contains any NSNull objects.

Exception with insertObject:atIndex: on iOS6

I'm getting the following Exception on iOS6 (on an App with CoreData):
"2012-10-15 10:21:28.952 MyApp[68650:c07] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
* First throw call stack:
(0x28e6012 0x2659e7e 0x2899b6a 0x2899a20 0x1646941 0x1642c67 0x164f846 0x164f908 0x6c540 0x2057e83 0x28a5376 0x28a4e06 0x288ca82 0x288bf44 0x288be1b 0x33967e3 0x3396668 0x15a165c 0x13a22 0x2845)
libc++abi.dylib: terminate called throwing an exception"
This doesn't happen on iOS5, so something happens on iOS6 what I don't understand.
I set a Breakpoint on every point where I call insertObject:atIndex: but these are not called - it have to be something in this libc++abi.dylib which gets called and crashes.
Does anyone know what could be wrong?
thank you
This is probably because either iOS5 did not throw an exception for this error (and should have, but now iOS6 throws one which is better than having erratic behavior later), or because you have some different behavior in iOS6 which makes your object nil whereas it was not in iOS5.
Whatever the reason, you can add a Symbolic Breakpoint on the insertObject:atIndex: symbol, so that it will break every time this method is called, wherever it is in your application (in your own code or not).
Go to the "Breakpoints Navigator" view (Cmd-6 shortcut)
Click on the "+" button to add a symbolic breakpoint
Set the symbolic breakpoint to break when it hits the symbol [NSArray insertObject:atIndex:]
Thus you can see when this is called with a nil value for the first parameter and fix your problem where it occurs.
You can also instead add an Exception Breakpoint to break when an exception is thrown, thus knowing when in the code your exception occurs. This is another way to let you know which part of the code (your own or another) generate the exception.
Once the breakpoint has been hit and the program stops before the exception occurs, you can check in the call stack what part of your own code led to trigger this exception at the end.
The reason for the crash is that the object you are trying to insert is nil. This means it is not properly instantiated. This in turn means something has gone awry before you reached that exception.
Could you post the code that alloced and initialized the object you were trying to insert?
In order to find the relevant line of code, please try the following: Go to the "Exception" tab in your Xcode project:
Then click the "+" button (at the bottom of the page) and select "Add Exception Breakppoint ...". Leave all settings to their defaults and click "Done".
If you rerun your project it should now stop at the relevant line of code before the exception is thrown. Then you can move up the call-stack and identify from where in your code you called the library function that is responsible for this behavior. Then try to see if all objects are correctly initialized at this point.

Resources