Swift:在 UITabView 之间传递数据并允许全局访问数据

Swift: Passing Data Between UITabViews & Allowing Global Access to Data

首先,让我解释一下我的应用程序及其流程。应用程序打开,用户创建配置文件(将所有数据存储在 [String: Any] 类型的字典中)。用户单击创建后,它将它们发送到控制台屏幕(显示用户输入的部分信息,例如通过 segue 显示他们的姓名)。有一个选项卡可以让他们编辑他们的个人资料(姓名、体重、地址等)。当用户编辑他们的信息(更改他们的姓名、体重等)时,它也应该更新控制台页面上显示的信息。

我的主要问题是,如何构造它以便数据对所有选项卡视图普遍可用。更具体地说,数据不是实例或数据的副本。我创建了一个名为 Person 的 class,其中存储了所有变量(firstNamelastName 等)。我已经尝试在 UIViewController class 声明之前将 person class 的实例声明为变量,但它不允许我使用 UITextField .text 属性(因为它们还没有被创建...?)。

这是我的人class...

class Person {

    var firstName: String
    var lastName: String
    var phoneNumber: String
    var weight: Int
    var gender: String
    var streetAddress: String
    var cityState: String

    init(firstName: String, lastName: String, phoneNumber: String, weight: Int, gender: String, streetAddress: String, cityState: String) {
        self.firstName = firstName
        self.lastName = lastName
        self.phoneNumber = phoneNumber
        self.weight = weight
        self.gender = gender
        self.streetAddress = streetAddress
        self.cityState = cityState
    }
}

我也将 UITabBarController 子class编辑为 TabBarViewController 因为我读到你可以将数据发送到那个子classed viewController 并使其对所有嵌入的选项卡普遍可用。我只是不知道它是如何工作的。

很抱歉可能会问一个重复的问题...我有 look/researched 这个问题,但我还没有找到适合我的特定情况的解决方案。

更新代码以将数据保存为 CoreData...

    guard let appDelegate =
        UIApplication.shared.delegate as? AppDelegate else {
            return
    }
    let managedContext = appDelegate.persistentContainer.viewContext
let userInfo = PInfo(firstName: firstNameField.text, lastName: lastNameField.text, cityState: cityStateField.text, streetAddress: streetAddressField.text, gender: genderInputField.text, userWeight: 200)

save(withPersonInfo: userInfo, withContext: managedContext)

我能够访问各种 viewControllers 中的数据,但它会将其作为单个项目数组返回给我...理想情况下,我希望将它们作为 key:value 对,这样我就可以轻松地将它们设置为在 Edit Profile viewController.

中显示和编辑

谢谢!

一个解决方案是Delegates。您获取数据的 class 将设置您的委托,以及希望获得该委托的任何其他人订阅该委托。

事实上:我认为使用 Delegate + CoreData 可能会让您免于麻烦;收听数据然后保存该数据。现在您的其他控制器将针对该用户场景进行快速获取(核心数据是如此之快,伙计:))

一些代码:

class PersonDetail: NSManagedObject { // this is how your coreData's Entity should look like 
    @NSManaged public var firstname: String?
    @NSManaged public var lastname:  String?

    // add the other fields, such as weight 

    @nonobjc public class func fetchRequest() -> NSFetchRequest<PersonDetail> {
        return NSFetchRequest<PersonDetail>(entityName: "PersonDetail")
    }
}
// This struct would to get the data from the user 
struct PInfo {
    var firstname:String?
    var lastname:String?
}
// this function would get an instance of that PInfo 
// for example var p = PInfo(firstname:"Stack",lastname:"Overflow")

func save(withPersonInfo p:PInfo, withContext context:NSManagedObjectContext) {
    let entityDescription = NSEntityDescription.entity(forEntityName: "PersonDetail", in: context)
    let managedObject = NSManagedObject(entity: entityDescription!, insertInto: context) as! PersonDetail
    // this is where I am passing data into the entity 
    managedObject.firstname = p.firstname
    managedObject.lastname = p.lastname

    try? context.save() // use the proper do {} catch, I was saving time lol :)

}
// when you fetch from coreData you have an instance of PInfo

func fetchSingleUser(withContext context:NSManagedObjectContext) -> PInfo {
    let request:NSFetchRequest<PersonDetail> = PersonDetail.fetchRequest()
    let coreData_items = try? context.fetch(request)

   guard let items = coreData_items,
       let firstItem = items.first  // since we only have one user
       else {  fatalError("Error while querying")  }

    return PInfo(firstname: firstItem.firstname, lastname:firstItem.lastname)
}

一个非常简单的解决方案是为您的应用委托一个 person 属性 初始化为一个空的 Person。这解决了问题,因为 every class 可以访问 属性:

let p = (UIApplication.shared.delegate as! AppDelegate).person

此外,p 通过引用获取此 Person,因此对其属性的任何更改都会反映回 person 属性 本身,以供查看(和变异)下一个视图控制器。

一个更复杂、更令人满意的解决方案,因为只有 一个 用户要配置,将让 Person class 本身分配一个 shared person 实例作为单例。 (在 SO 上搜索以了解如何在 Swift 中实现单例。)同样,该单例将普遍可用:

let p = Person.shared()