I have a logic regarding the content in the cells of a UITableView where at some point I call tableView.endUpdates(). The behavior of my scenario was the expected in iOS 10, but now in iOS 11 I am seeing that is behaving in a different way.
In iOS 10, user taps a cell, then I perform some logic and when tableView.endUpdates() is called, then tableView(_cellForRowAt:) is called once (at this point, 3 cells are shown in the screen and only one is being reused).
In iOS 11, user taps the cell (at this point, same 3 cells are shown in the screen), and after tableView.endUpdates() is called, tableView(_cellForRowAt:) is called 3 times. This is causing a behavior that it is not suitable for me.
Has somebody experienced an issue like this? How could I do in iOS 11 if I want to "refresh" the content only of the cell the user has tapped?
Related
I have developed a UITableViewController screen. It's working fine on Xcode 10.2 but. When I run on Xcode 11 beta 1 it's crashing like below.
I didn't find what was happening.
In ViewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
tableView.tableFooterView = UIView()
plateNoPrefix.becomeFirstResponder() // static cell textfield in tableViewcell
}
Exception… Attempted to access the table view's visibleCells while they were in the process of being updated, which is not allowed
I have faced the same issue when providing support for iOS 13.
This is a new exception in iOS 13 that UITableView will raise in order
to prevent and proactively alert you of a situation that would
previously cause undefined behaviour and a variety of strange,
seemingly unrelated, and hard-to-debug issues (including crashes).
What is happening here is that UITableView is in the middle of asking
its dataSource to return a cell for each visible row and is
configuring the properties of the returned cells so they can be
displayed. And in the middle of this updating -- most likely inside a
callback from the table view itself about a specific row such as
tableView(_:cellForRowAt:) tableView(_:canEditRowAt:), etc -- your
code is asking the table view to return the visible cells. This is
obviously problematic, because UITableView is right in the middle of
preparing those cells, so it cannot possibly return a meaningful
answer.
The fix for this is to look at where you are calling visibleCells in
the backtrace when this exception is raised, and then do one of two
things:
Option 1:
Move the usage of visibleCells to a better place, so that you aren't
asking for the visibleCells from someplace that is called during the
process of creating/configuring/updating those same cells. A great
place to ask for the visible cells is after the table view lays out,
so for example if the table view is the view of a view controller you
can use viewDidLayoutSubviews(), or in a subclass of UITableView do it
after calling super.layoutSubviews().
Option 2:
Depending on what you're actually trying to do, you might be able to
skip using visible cells altogether. For example, you might be able to
leverage the callbacks tableView(_:willDisplay:forRowAt:) and
tableView(_:didEndDisplaying:forRowAt:) to track when cells are
visible instead.
If you are hitting this exception and you think you are requesting the
visible cells from a location that should be valid/allowed, please
share the backtrace when you hit this exception and details about what
you're trying to do.
Update:
I am sure but plateNoPrefix.becomeFirstResponder() causing the crash. As of now, you can check by pasting this code in viewDidAppear method
OR
Execute this code after delay (Worked for me)
DispatchQueue.main.asyncAfter(deadline: .now()+0.1) {
// Your code
}
For details clerification you can refer Apple Developer Forum
This is a new exception in iOS 13 that UITableView will raise in order to prevent and proactively alert you of a situation that would previously cause undefined behavior and a variety of strange, seemingly unrelated, and hard-to-debug issues
Please have a look at Apple Developer Forum
I have a UICollectionView which should show thumbnails of photos received from a server, much like the Photo app in iOS.
When the cells disappear from the view and then re-appear, their positions are reversed up until the point the finger releases the screen.
As soon as the finger releases the screen, the cells get properly re-positioned as well.
I can't figure out why iOS does this.
In the following GIF you'll see the cells, and a label inside indicating their index in their section.
As you can see, the index changes as I explained above.
Why is this happening?
Btw ignore the sixth image, I was just drinking soup.
EDIT: I noticed a pattern when the line of cells re-enter the screen.
This pattern is not visible in the image above, so I'll just have to explain it in text.
Ok, so at start as you can see the index of the images are increasing, from 0 to 4, right?
As I hold the finger down and scroll the line of cells in and out of view
the cell indexes change to 3, 1, 4, 2, 0.
followed by the second re-entering which changes their
indexes to 2, 1, 0, 4, 3.
On the third re-entering they change to 4, 1, 3, 0, 2.
And finally on the fourth re-entering they change back
to original indexes 0,1,2,3,4.
This happens as long as I scroll the first line of cells in and out of view.
This is super-weird and makes no sense at all to me.
EDIT 2:
Ok, so it seems that the re-ordering of the cells to their correct index occurs only when the their images are changed/re-applied.
I added a variable which indicates if they've already been cached which I call bool TNCached, and upon cellForItemAtIndexPath I call a method from within the cell which is called requestTN, which in turn downloads the thumbnail of that specific cell from the server.
When the app fully receives the thumbnail, it sets the variable TNCached to TRUE, so next time the cell re-enters the view it won't re-download the thumbnail, thus not updating the cell, which causes the weird re-ordering of the cells indexes to persist even after I release my finger from the screen.
Edit 3:
Yaaay fixed it!
Turns out that the re-use of my UICollectionView cells is the "problem".
Not really a problem, but whenever a cell is reused, the UICollectionView reuses random cells of any given cell of the ones that disappeared when scrolled outside the screen.
So my question now is if the efficiency of my re-use of cells is maybe not that efficient?
What's happening is that your cells are being re-used,
which means that any of the cells that have disappeared from the screen can be used again, in any order.
What you need to do at cellForItemAtIndexPath is to setup your cell again.
By "setup" I mean to take the information from the data-source and apply it to your cell again.
So if cell 0 re-appears at NSIndexPath section 0 and item 4, then you simply go to your datasource and read the data that should be presented at NSIndexPath section 0 and item 4.
I ask this because I find it's strange that heightForRowAtIndexPath firstly work with the last cell in my tableView.
Here's what I got, I've 13 sections, each section has only one cell. So when I called reloadData and log the indexPath.section in heightForRowAtIndexPath, the last section's indexPath got printed. Then it started from section 0, then 1, 2, 3, till 11 in order.
This is tested on both device & simulator and both iOS 7 & iOS 8.
Is this the fixed order or only for the case that I test?
Apple doesn't specify the order in which -tableView:heightForRowAtIndexPath: is called.
This means you cannot rely on any particular order. When you call -endUpdates, or any of the reload/insert/delete/move methods, the row heights will be recalculated. UITableView may take advantage of special knowledge (like the currently visible cells) and recalculated row heights in a different order.
Worse, even if you test every version of iOS on every Apple device and get the exact same order every time, the next point release could change it.
If you are using AutoLayout . Fix Constrains Properly . They might make the difference. In iOS * you don't even have to use -tableView:heightForRowAtIndexPath:.
I’m using VoiceOver, and having an issue with a UICollectionView. I have an initial screen with ten buttons, each of which links through to one of ten cells in the collection view. The collection view is actually the full size of the screen, and each cell contains a child view controller. This all works fine with VoiceOver switched off, but when it’s switched on, activating one of the buttons in the middle of the set always causes the collection view to pop to its first cell, even if I didn’t tap the first button. I think this is because the VoiceOver “focus” goes to the first element it sees (i.e. the first cell).
I’ve tried using the UIAccessibilityScreenChangedNotification and the same with Layout with an argument of the cell in question, but it’s making no difference, it’s not popping to my required element, and is always popping to the first cell in the collection.
What could I be doing wrong here?
I’m adding a snippet, this is called in viewDidLayoutSubviews, and works fine for the actual scrolling if VoiceOver is turned off. But as soon as VO is on, it breaks.
if (self.initialIndexPath) {
[self.collectionView scrollToItemAtIndexPath:self.initialIndexPath atScrollPosition:UICollectionViewScrollPositionNone animated:NO];
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, [self.collectionView cellForItemAtIndexPath:self.initialIndexPath]);
}
This works absolutely fine for actually focusing on the cell, but the VoiceOver portion is completely ignored, the notification does not shift the focus to that correct cell at all, it's always the first element in the first cell.
Also to note, the cells themselves are NOT accessibilityElements and should not be, they implement the UIAccessibilityContainer protocol, and so the title label of each cell would be where I'd like the focus to end up.
This was a bug in iOS and is fixed now.
I started to see this bug in iOS8. And reported a bug to Apple about this 6. Nov 2014.
Was fixed in iOS 9.3.2.
There is nothing you can do as developer if you are on affected OS version. Recommend users of your app to update the OS.
I have create custom cell in table view. Each cell is different in terms of UI. I have craetd three cell and identifier for each cell is different. The custom table view cell are not released when I called the method "reloadRowsAtIndexPaths". Here is the link of my project source code
http://www.megafileupload.com/en/file/486016/TableVIewTestSample-zip.html
or
http://www.2shared.com/file/PgExc8W_/TableVIewTestSample.html
When run the code click on "Push" button on the screen and then wait 4 second at the 2nd screen and click back button. The cell are not released.
Can anybody run the code and suggest any fix for this.
I haven't looked at your code but cells aren't necessarily released when you reload. Cells are built to be re-used, so just reloading the data doesn't necessarily free the old cells. (There's no reason to free and re-create a cell if you've already created enough cells.)
In general if you create a tableView and scroll around you shouldn't see any cells released. You should see them released only when you nuke the tableView (that's when it's sure it won't need them again) and a few other situations.
(On the other hand, you might just be leaking the cells.)
This issue exist in iOS 7.0.0 to iOS 7.0.2. The cells do not release when we perform the "reloadRowsAtIndexPaths" method. This issue is solved in iOS 7.0.3.