I'm currently implementing automatic state preservation/restoration in an iOS6-only app.
For a restoration of a table view, I added the UIDataSourceModelAssociation
protocol to my table view controllers and implemented
- (NSString *)modelIdentifierForElementAtIndexPath:(NSIndexPath *)idx inView:(UIView *)view
and
- (NSIndexPath *)indexPathForElementWithModelIdentifier:(NSString *)identifier inView:(UIView *)view
When pressing the home button, the state preservation methods, including modelIdentifierForElementAtIndexPath:iView:
, are getting called as expected and return valid identifier strings for the given index paths.
When killing the app and relaunching it, state restoration works more or less. I.e. the app re-opens the correct table view. However, the table view is always scrolled to the top, even when it was scrolled to another position before.
Here's the implementation of the UIDataSourceModelAssociation
methods in my table view controller. Nothing fancy going on in there (the NdlFriend::accountUid
property returns a unique identifier string for a given NdlFriend record):
#pragma mark - UIDataSourceModelAssociation
- (NSString *)modelIdentifierForElementAtIndexPath:(NSIndexPath *)idx inView:(UIView *)view
{
NSString* identifier = nil;
NSArray* content = self.contentArray;
// Sometimes idx might be nil...
if(idx && idx.row<content.count)
{
NdlFriend* friend = content[idx.row];
identifier=friend.accountUid;
}
return identifier;
}
- (NSIndexPath *)indexPathForElementWithModelIdentifier:(NSString *)identifier inView:(UIView *)view
{
NSIndexPath * indexPath=nil;
NSArray* content = self.contentArray;
NSInteger count = content.count;
for(NSInteger i=0;i<count;i++)
{
NdlFriend* friend = content[i];
if([identifier isEqualToString:friend.accountUid])
{
indexPath = [NSIndexPath indexPathForRow:i inSection:0];
break;
}
}
return indexPath;
}
I set break points in both methods.
To test the methods, I opened the table view and scrolled down a little bit. Then, when pressing the home button:
modelIdentifierForElementAtIndexPath:inView:
gets called once, with the index path of the top most visible row. The method returns the correct uid for this row.So far so good.
Then I stop and relaunch the app. Here's what happens (I'm especially puzzled by the first hit break point):
modelIdentifierForElementAtIndexPath:inView:
gets called, with nil
as index path (the view argument contains the correct pointer of the table view).indexPathForElementWithModelIdentifier:inView:
gets called with a valid identifier string (and a valid index path is returned by the method).indexPathForElementWithModelIdentifier:inView:
gets called again (with the same identifier string).Does someone know, why the restoration of the scroll position fails? Does maybe the call of modelIdentifierForElementAtIndexPath:inView:
with nil
as indexPath has something to do with it (or is this normal behavior).
There is a bug in iOS 6 regarding state restoration of Table Views in Navigation Controllers.
You can see the open radar here: rdar://13438788
As you can see, it's a duplicate, so Apple are aware of this.
Also, see this next link, the guy who posted that open radar also did this blog post, it has the suggested workarounds that the Apple Engineers told him.
It makes the state preservation/restoration for me not such an enjoyable feature to implement, although remember, this is for your users ! So you should just do the workaround anyway.
Note there are 2 workarounds, one for the table view's view information to restore (scroll offset for example), and another workaround for the use when implementing UIDataSourceModelAssociation
which is your case.
http://useyourloaf.com/blog/2013/04/07/bug-table-view-state-not-restored-when-embedded-in-navigation-controller.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With