gpt4 book ai didi

arrays - Swift 数组字典、数据结构

转载 作者:行者123 更新时间:2023-11-30 10:06:09 26 4
gpt4 key购买 nike

我正在编写一个简单的程序,可以让我监控 iOS 应用程序中的一些销售情况。基本上,我需要一种允许客户(作为字符串)的数据结构,并且对于每个客户,我需要能够保存一个或多个“销售”,每个销售由销售日期和价格组成。我将其实现为一个 Swift 字典,它在单例 Swift 类中读取和保存到 plist 文件,因为我需要从多个 View Controller 读取和写入相同的数据结构。这是数据类的代码:

import Foundation
import UIKit

class DataSingleton {

static let sharedDataSingleton = DataSingleton()
private(set) var allData = [String: [AnyObject]]()
private(set) var customers: [String] = []

init() {
let fileURL = self.dataFileURL()
if (NSFileManager.defaultManager().fileExistsAtPath(fileURL.path!)) {
allData = NSDictionary(contentsOfURL: fileURL) as! [String : [AnyObject]]
customers = allData.keys.sort()
}
}

func dataFileURL() -> NSURL {
let url = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
return url.first!.URLByAppendingPathComponent("data.plist")
}

func addCustomer(customerName: String) {
if !customers.contains(customerName) {
customers.append(customerName)
allData[customerName] = [[NSDate(), 0]]
saveData()
}
}

func addSale(customerName: String, date: NSDate, price: Int) {
allData[customerName]?.append([date, price])
saveData()
}

func saveData() {
let fileURL = self.dataFileURL()
let customerData = allData as NSDictionary
customerData.writeToURL(fileURL, atomically: true)
}
}

正如你所看到的,我使用了一个字典,其中客户名称是键,销售额是 AnyObject 的数组。我怀疑这是否是实现此目的的最佳和最优雅的方式,所以也许有人可以帮助我解决以下问题:

  1. 什么是更好的实现方法?将 sales 实现为一个结构体,然后使用该结构体的数组是否有意义?

  2. 创建新客户时,我需要使用占位符

    allData[customerName] = [[NSDate(), 0]]

因为没有值的字典键不会被保存。有更好的方法吗?

  • 为什么 allData.keys.sort() 会生成字符串数组,而 allData.keys 不会?这对我来说没有意义,因为排序函数似乎不应该更改类型。

  • 在我的(表) View 中,每个单元格显示一个客户以及每个客户的总销售额。我想按销售总额对该表进行排序。当前代码(参见 3.)按字母顺序对客户进行排序。实现此目的的最佳方法是什么:按数据结构本身或 View Controller 中的总销售额对客户进行排序?有人可以提供代码如何最优雅地实现这种排序,也许使用排序函数和闭包?

  • 最佳答案

    看看您的代码编辑,看看它是否适合您的目的:

    import Foundation

    /// Allows any object to be converted into and from a NSDictionary
    ///
    /// With thanks to [SonoPlot](https://github.com/SonoPlot/PropertyListSwiftPlayground)
    protocol PropertyListReadable {
    /// Converts to a NSDictionary
    func propertyListRepresentation() -> NSDictionary

    /// Initializes from a NSDictionary
    init?(propertyListRepresentation:NSDictionary?)
    }

    /// Converts a plist array to a PropertyListReadable object
    func extractValuesFromPropertyListArray<T:PropertyListReadable>(propertyListArray:[AnyObject]?) -> [T] {
    guard let encodedArray = propertyListArray else {return []}
    return encodedArray.map{$0 as? NSDictionary}.flatMap{T(propertyListRepresentation:$0)}
    }

    /// Saves a PropertyListReadable object to a URL
    func saveObject(object:PropertyListReadable, URL:NSURL) {
    if let path = URL.path {
    let encoded = object.propertyListRepresentation()
    encoded.writeToFile(path, atomically: true)
    }
    }

    /// Holds the information for a sale
    struct Sale {
    let date:NSDate
    let price:Int
    }

    /// Allows a Sale to be converted to and from an NSDictionary
    extension Sale: PropertyListReadable {
    /// Convert class to an NSDictionary
    func propertyListRepresentation() -> NSDictionary {
    let representation:[String:AnyObject] = ["date":self.date, "price":self.price]
    return representation
    }

    /// Initialize class from an NSDictionary
    init?(propertyListRepresentation:NSDictionary?) {
    guard let values = propertyListRepresentation,
    date = values["date"] as? NSDate,
    price = values["price"] as? Int else { return nil }
    self.init(date:date, price:price)
    }
    }

    /// Singleton that holds all the sale Data
    final class DataSingleton {
    /// Class variable that returns the singleton
    static let sharedDataSingleton = DataSingleton(dataFileURL: dataFileURL)

    /// Computed property to get the URL for the data file
    static var dataFileURL:NSURL? {
    get {
    let manager = NSFileManager.defaultManager()
    guard let URL = manager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first?.URLByAppendingPathComponent("data.plist"),
    path = URL.path else { return nil }
    let data = NSKeyedArchiver.archivedDataWithRootObject([String:AnyObject]())
    guard manager.fileExistsAtPath(path) &&
    manager.createFileAtPath(path, contents: data, attributes: nil) else { return nil }
    return URL
    }
    }

    /// The dictionary holding all the sale data
    private(set) var allData:[String: [Sale]]

    /// Computed property to return all the customers
    var customers:[String] { get { return Array(allData.keys) }}

    /// Designated initializer
    ///
    /// Made private to disallow additional copies of the singleton
    private init() { allData = [:] }

    /// Adds a customer to the data dictionary
    func addCustomer(customerName: String) {
    if allData[customerName] == nil {
    allData[customerName] = []
    saveData()
    }
    }

    /// Adds a sale to the data dictionary, creating a new customer if neccesary
    func addSale(customerName: String, date: NSDate, price: Int) {
    addCustomer(customerName)
    allData[customerName]?.append(Sale(date: date, price: price))
    saveData()
    }

    // Saves the singleton to the plist file
    private func saveData() {
    if let fileURL = DataSingleton.dataFileURL {
    saveObject(self, URL: fileURL)
    }
    }
    }

    /// Allows a DataSingleton to be converted to and from an NSDictionary
    extension DataSingleton: PropertyListReadable {
    /// Convert class to an NSDictionary
    func propertyListRepresentation() -> NSDictionary {
    return allData.reduce([String:[AnyObject]]()) {
    var retval = $0
    retval[$1.0] = $1.1.map {$0.propertyListRepresentation()}
    return retval
    }
    }

    /// Initialize class from a plist file
    ///
    /// Made private to disallow additional copies of the singleton
    private convenience init?(dataFileURL: NSURL?) {
    guard let fileURL = dataFileURL,
    path = fileURL.path where (NSFileManager.defaultManager().fileExistsAtPath(path)),
    let data = NSDictionary(contentsOfFile: path) else { return nil }
    self.init(propertyListRepresentation: data)
    }

    /// Initialize class from an NSDictionary
    convenience init?(propertyListRepresentation:NSDictionary?) {
    self.init() // satisfies calling the designated init from a convenience init
    guard let values = propertyListRepresentation else {return nil}
    allData = values.reduce([:]) {
    var retvalue = $0
    guard let key = $1.key as? String,
    value = $1.value as? [AnyObject] else { return retvalue }
    retvalue[key] = extractValuesFromPropertyListArray(value)
    return retvalue
    }
    }
    }

    用法:

    let data = DataSingleton.sharedDataSingleton
    data?.addSale("June", date: NSDate(), price: 20)
    data?.addSale("June", date: NSDate(), price: 30)

    let data2 = DataSingleton.sharedDataSingleton
    print(data2?.allData["June"])
    // => Optional([Sale(date: 2016-03-10 04:31:49 +0000, price: 20), Sale(date: 2016-03-10 04:31:49 +0000, price: 30)])

    要回答 3,您应该注意 allData.keys 的返回值。这是一个惰性集合,在您请求之前不会提取值。调用sort它会提取所有值,因为没有它们就无法排序。因此,它返回一个常规的、非惰性的 Array 。您无需使用 sort 即可获得非惰性数组通过这样做:Array(allData.keys)

    评论中您的其他问题:

    1:希望能修复,我从 NSCoding 切换过来了因为它依赖于 NSObjectNSData 。这意味着我们不能使用 struct以其非常理想的value semantics等问题。

    2:通过扩展添加功能是个好主意。这允许您保持代码划分,例如我添加了对 protocol 的合规性PropertyListReadableextension然后在那里添加必要的方法。

    3:在此代码中allData初始化于 init?(propertyListRepresentation:) 。那里有一个NSDictionary被读取,每个客户及其销售额被解析为正确的数据结构。自从我改变Sale来自classstruct (感谢新的 protocol PropertyListReadable )我们可以声明它保存的变量和 init方法是自动为我们生成的 init(date:NSDate, price:Int)

    一个struct喜欢 SaleDictionary 更好由于类型检查、自动完成、能够更好地注释 struct并自动生成文档、验证值的可能性、添加附加功能的协议(protocol)等等。很难确切地知道旧的是什么 Dictionary代表它何时被埋藏在代码中并具有具体的 struct , enum ,或class让您的生活变得更加轻松。

    一个Dictionary非常适合将键映射到值,但是当您想要将多个相互依赖的值保存在一起时,您需要查看 enum , structclass .

    关于arrays - Swift 数组字典、数据结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35850308/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com