From 773af9361e826d72e6f9fe117410b2829d2fd69d Mon Sep 17 00:00:00 2001 From: Jonathan Schleifer Date: Thu, 20 Jun 2019 01:15:26 +0200 Subject: [PATCH] iOS: Make more use of native Swift types --- iOS/AddSiteController.swift | 25 ++------ iOS/MainViewController.swift | 6 +- iOS/ShowDetailsController.swift | 17 +++--- iOS/SiteStorage.swift | 100 ++++++++++++++------------------ 4 files changed, 61 insertions(+), 87 deletions(-) diff --git a/iOS/AddSiteController.swift b/iOS/AddSiteController.swift index 2485f8e..644908c 100644 --- a/iOS/AddSiteController.swift +++ b/iOS/AddSiteController.swift @@ -62,28 +62,16 @@ class AddSiteController: UITableViewController { } @IBAction func done(_ sender: Any) { - guard let name = nameField?.text?.ofObject else { return } - guard let lengthString = lengthField?.text?.ofObject else { return } + guard let name = nameField?.text else { return } + guard let lengthString = lengthField?.text else { return } - guard name.length > 0 else { + guard name.count > 0 else { showAlert(controller: self, title: "Name missing", message: "Please enter a name.") return } - var lengthValid = true - var length: size_t = 0 - OFException.try({ - length = lengthString.decimalValue - - if length < 3 || length > 64 { - lengthValid = false - } - }, catch: { (OFException) in - lengthValid = false - }) - - guard lengthValid else { + guard let length = UInt(lengthString), length >= 3, length <= 64 else { showAlert(controller: self, title: "Invalid length", message: "Please enter a number between 3 and 64.") return @@ -97,10 +85,9 @@ class AddSiteController: UITableViewController { return } - let keyFile = self.keyFile?.ofObject siteStorage.setSite(name, length: length, - legacy: legacySwitch?.isOn ?? false, - keyFile: keyFile) + isLegacy: legacySwitch?.isOn ?? false, + keyFile: self.keyFile) mainViewController?.reset() navigationController?.popViewController(animated: true) } diff --git a/iOS/MainViewController.swift b/iOS/MainViewController.swift index 3c29ac6..2e71cf5 100644 --- a/iOS/MainViewController.swift +++ b/iOS/MainViewController.swift @@ -25,7 +25,7 @@ import ObjFW class MainViewController: UIViewController, UISearchBarDelegate, UITableViewDelegate, UITableViewDataSource { - public var sites = OFArray() + public var sites: [String] = [] public var siteStorage = SiteStorage() @IBOutlet var searchBar: UISearchBar? @IBOutlet var tableView: UITableView? @@ -51,12 +51,12 @@ class MainViewController: UIViewController, UISearchBarDelegate, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "site") ?? UITableViewCell(style: .default, reuseIdentifier: "site") - cell.textLabel?.text = sites[indexPath.row].nsObject + cell.textLabel?.text = sites[indexPath.row] return cell } func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { - sites = siteStorage.sites(withFilter: searchBar.text?.ofObject) + sites = siteStorage.sites(withFilter: searchBar.text) tableView?.reloadData() } diff --git a/iOS/ShowDetailsController.swift b/iOS/ShowDetailsController.swift index d4d9ec5..895064a 100644 --- a/iOS/ShowDetailsController.swift +++ b/iOS/ShowDetailsController.swift @@ -32,10 +32,10 @@ class ShowDetailsController: UITableViewController, UITextFieldDelegate { @IBOutlet var passphraseField: UITextField? public var mainViewController: MainViewController? - private var name: OFString = "".ofObject - private var length: size_t = 0 + private var name: String = "" + private var length: UInt = 0 private var isLegacy: Bool = false - private var keyFile: OFString? = nil + private var keyFile: String? = nil override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) @@ -50,10 +50,10 @@ class ShowDetailsController: UITableViewController, UITextFieldDelegate { isLegacy = siteStorage.isLegacy(site: name) keyFile = siteStorage.keyFile(forSite: name) - nameField?.text = name.nsObject + nameField?.text = name lengthField?.text = "\(length)" legacySwitch?.isOn = isLegacy - keyFileField?.text = keyFile?.nsObject + keyFileField?.text = keyFile tableView.deselectRow(at: indexPath, animated: true) } @@ -134,8 +134,8 @@ class ShowDetailsController: UITableViewController, UITextFieldDelegate { private func generateWithCallback(_ block: (_: NSMutableString) -> ()) { let generator: PasswordGenerator = isLegacy ? LegacyPasswordGenerator() : NewPasswordGenerator() - generator.site = name - generator.length = length + generator.site = name.ofObject + generator.length = size_t(length) if let keyFile = keyFile { guard let documentDirectory = NSSearchPathForDirectoriesInDomains( @@ -145,7 +145,8 @@ class ShowDetailsController: UITableViewController, UITextFieldDelegate { return } - let keyFilePath = documentDirectory.ofObject.appending(keyFile) + let keyFilePath = + documentDirectory.ofObject.appending(keyFile.ofObject) generator.keyFile = OFMutableData(contentsOfFile: keyFilePath) } diff --git a/iOS/SiteStorage.swift b/iOS/SiteStorage.swift index fdf8a09..619e13e 100644 --- a/iOS/SiteStorage.swift +++ b/iOS/SiteStorage.swift @@ -24,16 +24,13 @@ import ObjFW import ObjFWBridge class SiteStorage: OFObject { - private typealias Storage = - OFMutableDictionary> - - private static let lengthField = OFNumber(uInt8: 0) - private static let legacyField = OFNumber(uInt8: 1) - private static let keyFileField = OFNumber(uInt8: 2) + private static let lengthField = NSNumber(value: 0) + private static let legacyField = NSNumber(value: 1) + private static let keyFileField = NSNumber(value: 2) private var path: OFString - private var storage: Storage - private var sites: OFArray + private var storage: [String: [NSNumber: AnyObject]] + private var sites: [String] override init() { let fileManager = OFFileManager.default @@ -45,91 +42,80 @@ class SiteStorage: OFObject { let path = userDataPath.appendingPathComponent( OFString(utf8String: "sites.msgpack")) - var storage: Storage? = nil + + var storage: [String: [NSNumber: AnyObject]]? = nil OFException.try({ - storage = OFData(contentsOfFile: path).messagePackValue as? Storage + let decoded = (OFData(contentsOfFile: path).messagePackValue) + as? OFDictionary> + storage = + (decoded?.nsObject as? [String: [NSNumber: AnyObject]]) ?? [:] }, catch: { (OFException) in - storage = OFMutableDictionary() + storage = [:] }) self.path = path self.storage = storage! - self.sites = self.storage.allKeys.sorted + self.sites = self.storage.keys.sorted() } - func sites(withFilter filter: OFString?) -> OFArray { - // FIXME: We need case folding here, but there is no method for it yet. - let filter = filter?.lowercase - - return storage.allKeys.sorted.filteredArray({ - (name: Any, index: size_t) -> Bool in - if filter == nil { - return true + func sites(withFilter filter: String?) -> [String] { + return storage.keys.sorted().filter({ (name) in + if let filter = filter { + return name.localizedCaseInsensitiveContains(filter) } - - let name = name as! OFString - return name.lowercase.contains(filter!) + return true }) } - func hasSite(_ name: OFString) -> Bool { + func hasSite(_ name: String) -> Bool { return (storage[name] != nil) } - func length(forSite name: OFString) -> size_t { + func length(forSite name: String) -> UInt { guard let site = storage[name] else { OFInvalidArgumentException().throw() } - return (site[SiteStorage.lengthField] as! OFNumber).sizeValue + return (site[SiteStorage.lengthField] as! NSNumber).uintValue } - func isLegacy(site name: OFString) -> Bool { - guard let site = storage[name] else { - OFInvalidArgumentException().throw() - } - - return (site[SiteStorage.legacyField] as! OFNumber).boolValue + func isLegacy(site name: String) -> Bool { + guard let site = storage[name] else { return false } + return (site[SiteStorage.legacyField] as! NSNumber).boolValue } - func keyFile(forSite name: OFString) -> OFString? { - guard let site = storage[name] else { - OFInvalidArgumentException().throw() - } + func keyFile(forSite name: String) -> String? { + guard let site = storage[name] else { return nil } - let keyFile = site[SiteStorage.keyFileField] - if keyFile is OFNull { + guard let keyFile = site[SiteStorage.keyFileField], !(keyFile is NSNull) + else { return nil } - return keyFile as? OFString + return keyFile as? String } - func setSite(_ name: OFString, length: size_t, legacy: Bool, - keyFile: OFString?) { - let siteDictionary = OFMutableDictionary() - - siteDictionary.setObject(OFNumber(size: length), - forKey: SiteStorage.lengthField) - siteDictionary.setObject(OFNumber(bool: legacy), - forKey: SiteStorage.legacyField) - if keyFile != nil { - siteDictionary.setObject(keyFile!, forKey: SiteStorage.keyFileField) - } - - siteDictionary.makeImmutable() - storage.setObject(siteDictionary, forKey: name) + func setSite(_ name: String, length: UInt, isLegacy: Bool, + keyFile: String?) { + var siteDictionary: [NSNumber: AnyObject] = [ + SiteStorage.lengthField: NSNumber(value: length), + SiteStorage.legacyField: NSNumber(value: isLegacy), + ] + siteDictionary[SiteStorage.keyFileField] = keyFile as AnyObject? + storage[name] = siteDictionary self.update() } - func removeSite(_ name: OFString) { - self.storage.removeObject(forKey: name) + func removeSite(_ name: String) { + storage[name] = nil self.update() } private func update() { - storage.messagePackRepresentation.write(toFile: path) - sites = storage.allKeys.sorted + let ofStorage = (storage as NSDictionary).ofObject + + ofStorage.messagePackRepresentation.write(toFile: path) + sites = storage.keys.sorted() } }