简体   繁体   中英

How to save NSIndexPath locally?

I can get the first row of visible cells in a table view by:

let topRow = tableView?.indexPathsForVisibleRows![0]

I want to save this NSIndexPath so that when the app starts next time, the table view can scroll to the same position just like where it was left.

I think I should save topRow.row and topRow.section. Is there anything else? Or is there any better way?

For this kind of thing using NSUserDefaults is not a bad idea. I suggest reading this post for detailed information.

TLDR;

let defaults = NSUserDefaults.standardUserDefaults()
defaults.setInteger(indexPath.row, forKey: "LastVisibleRowKey")
defaults.setInteger(indexPath.section, forKey: "LastVisibleSectionKey")

In order to retrieve the saved items you do:

let row = defaults.integerForKey("LastVisibleRowKey")

I hope that helps.

NSIndexPath implements the NSSecureCoding protocol. This means that you can use NSKeyedArchiver and NSKeyedUnarchiver to convert the index path to data that can be stored in a plist or user defaults.

The pattern is described here: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/DrawColor/Tasks/StoringNSColorInDefaults.html

Example:

extension NSUserDefaults {
    func indexPathForKey(key: String) -> NSIndexPath? {
        if let data = self.objectForKey(key) as? NSData {
            if let indexPath = NSKeyedUnarchiver.unarchiveObjectWithData(data) as? NSIndexPath {
                return indexPath
            }
        }
        return nil;
    }

    func setIndexPath(indexPath: NSIndexPath, forKey key:String) {
        self.setObject(NSKeyedArchiver.archivedDataWithRootObject(indexPath), forKey: key)
    }
}

let defaults = NSUserDefaults.standardUserDefaults()

//
// Saving an index path
//
let myIndexPath = NSIndexPath(indexes:[1, 2, 3, 4], length: 4)
defaults.setIndexPath(myIndexPath, forKey:"MyIndexPath")

//
// Loading an index path
//
if let newIndexPath = defaults.indexPathForKey("MyIndexPath") {
    print("Loaded index path: \(newIndexPath)")
    assert(myIndexPath == newIndexPath)
}

You can use NSKeyedArchiver archiveRootObject to write your index data to a plist file at the library preferences directory and unarchive it using NSKeyedUnarchiver unarchiveObjectWithFile . Just create a property called lastSelectedIndex with a getter and a setter to save and load it automatically:

var lastSelectedIndex: NSIndexPath? {
    get {
        guard
            let filePath = NSFileManager().URLsForDirectory(.LibraryDirectory, inDomains: .UserDomainMask).first?.URLByAppendingPathComponent("Preferences", isDirectory: true).URLByAppendingPathComponent("myAppData.plist").path
        else { return nil }
        return NSKeyedUnarchiver.unarchiveObjectWithFile(filePath) as? NSIndexPath
    }
    set {
        guard
            let newValue = newValue,
            filePath = NSFileManager().URLsForDirectory(.LibraryDirectory, inDomains: .UserDomainMask).first?.URLByAppendingPathComponent("Preferences", isDirectory: true).URLByAppendingPathComponent("myAppData.plist").path
        else { return }
        NSKeyedArchiver.archiveRootObject(newValue, toFile: filePath)
    }
}

In your method didSelectRowAtIndexPath set your lastSelectedIndex:

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    lastSelectedIndex = indexPath
    // your code
}

And load it as follow:

override func viewDidLoad() {
    super.viewDidLoad()
    guard let lastSelectedIndex = lastSelectedIndex else { return }
    tableView.selectRowAtIndexPath(lastSelectedIndex, animated: false, scrollPosition: .None)
}

A better way would be to use State Restoration , instead of trying to persist UIKit state on your own.

The App Programming Guide for iOS documentation covers how to enable state preservation and restoration for your app.

From the user's perspective, quitting an app should just seem like a temporary interruption. When the user returns to an app, that app should always return the user to the last point of use, so that the user can continue with whatever task was in progress. This behavior provides a better experience for the user and with the state restoration support built in to UIKit is relatively easy to achieve.

The state preservation system in UIKit provides a simple but flexible infrastructure for preserving and restoring the state of your app's view controllers and views.

As you can see, it can preserve far more than just a tableView's content offset, for you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM