Reputation: 137
First off, let me explain my app and its flow. The app opens, and the user creates a profile (stores all the data in a dictionary of type [String: Any]
). After the user clicks on create, it sends them to a Console Screen (which displays parts of the information the user input, such as their name through a segue
). Theres a tab that lets them EDIT their profile (name, weight, address, etc). When the user edits their info (to change their name, weight, etc), it should also update the info displayed on the Console Page.
My main question is, how do I structure it so the data is universally available to all of the tab views. More specifically, so the data is NOT an INSTANCE or copy of the data. I've created a class called Person
which has all of the variables stored in it (firstName
, lastName
, etc). I've tried declaring the instance of the person class as a variable before the UIViewController
class declaration, but it won't let me use the UITextField
.text
property (because they havent been created yet...?).
Here is my Person 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
}
}
I have also subclassed the UITabBarController
as TabBarViewController
because I've read that you can send the data to that subclassed viewController
and make it universally available to all of the imbedded tabs. I'm just at a loss as to how it all works.
I apologize for possibly asking a repeat question...I have look/researched this and I haven't found any suitable solutions for my particular case.
Updated code to save data as 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)
I'm able to access the data in various viewControllers
, but it gives it back to me as a single item array... Ideally, I'd like to have them as key:value
pairs so I can easily set them to display and are editable in the Edit Profile
viewController
.
Thanks!
Upvotes: 0
Views: 81
Reputation: 3030
One solution would be Delegates
. The class where you are getting the data would sets your delegate, and anyone else who wishes to get that subscribe to that delegate.
As matter of fact: I think using Delegate + CoreData
might save you from troubles; Listen for data then saved that data. Now your other controllers will do a quick fetch (core data is so fast man:) for that one user scenario )
Some code:
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)
}
Upvotes: 0
Reputation: 535129
One very easy solution is to give your app delegate a person
property initialized as an empty Person. This solves the problem because every class can access that property:
let p = (UIApplication.shared.delegate as! AppDelegate).person
Moreover, p
obtains this Person by reference, so any changes to its properties are reflected back into the person
property itself, ready to be seen (and mutated) by the next view controller.
A more sophisticated, satisfying solution, since there is only one user to be configured, would be to have the Person class itself dispense a shared
person instance as a singleton. (Do a search on SO to learn how to implement Singleton in Swift.) Again, that singleton will be universally available:
let p = Person.shared()
Upvotes: 1