Array Data Through Different View Controllers Swift - ios

Hey guys I'm working on my first ever app and need some help. My workout tracker app has two classes which you can find below. I have two view controllers hooked up to their own swift files.
Heres my first view controller
Basically what it does is takes the data in the text fields and steppers and turns it into a "Workout" object then appends it to the "WorkoutList" class array.
I've got a print statement setup that prints the Array.count. It shows the correct number in the debug but when I switch views it gets reset to zero.
#IBAction func addToWorkoutList(_ sender: UIButton) {
let workout = Workout(name: workoutName.text!, description: workoutDescription.text!, sets: Int(setStepper.text!)!, reps: Int(repStepper.text!)!)
workoutArrayList.append(workout)
print(workoutArrayList.count)
}
The second view inherits the first views class so that is how I access the "WorkoutArrayList"
class OverViewViewController: NewWorkoutViewController, UITableViewDelegate, UITableViewDataSource {
My app basically allows you to add a workout then produces a graph based on the data you provided. This can make it easy to visualize your gains in the gym. I'm doing this as a learning project so any help on what I should do to build this app would also be greatly appreciated.
Workout Object Class
import Foundation
class Workout {
let workoutName : String
let workoutDescription : String
let numberOfSets : Int
let numberOfReps : Int
init(name : String, description : String, sets : Int, reps : Int) {
workoutName = name
workoutDescription = description
numberOfSets = sets
numberOfReps = reps
}
}
WorkoutList Class
import Foundation
class WorkoutList {
let workoutArray : [Workout] = []
}

Inheriting the class is not what you want to do here. An easy fix for you would be to make workoutArray a static variable so any class can access it at any given time.
static var workoutArray : [Workout] = []
Here is why just inheriting the class doesn't work. When the OverViewViewController loads in to the app, it creates a new instance of the class OverViewViewController and since it inherits NewWorkoutViewController, it also creates a new instance of the NewWorkoutViewController class. You have 2 different instances of NewWorkoutViewController, changing a variable in one of those instances won't change it for any other instances of the class. A static variable, however, is what you are looking for. The array can be changed and accessed any time from any class, you don't even need to inherit. It would work whether you made workoutArray static or workoutArrayList static.
If you have any other questions, feel free to leave a comment.

Related

Is there any way to optimize struct copy in Swift?

I'm developing an iOS app and have the following data model:
struct Student {
var name: String?
var age: UInt?
var hobbies: String?
...
}
This model is used as the data source in one view controller, where each property value will be filled in an UITextfield instance so that the user can edit a student's information. Every time a user finishes typing an item, e.g. the name, the new value will override the old model's corresponding property.
The problem is, since struct is a value type instead of a reference type, a new model instance is generated every time I assign a new property value to it. There may be above 20 properties in my model and I think so many copies are quite a waste. For some reasons I'm not allowed to use class. Is there any way to optimize this? Will these copies cause any performance issues?
you can create a func with mutating keyword like below
struct Point {
var x = 0.0
mutating func add(_ t: Double){
x += t
}
}
find more here

Best Approach to Refresh a Class [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
Simply i want to know what is the Best Approach to refresh a class.Like when same class is used from diff-diff section of application where we pass some data to that class ,I can do it by simply taking a global variable and change it's value from other class's But i want to know some another approach which is best suitable for this kind of Things.
The best way to handle this kind of structure, where the class needs to be effectively shared between other MVCs, is to make the class a singleton. This means that only one instance of a class is ever used. That way if one MVC changes the class you don't need to sync the change because every MVC uses the same instance.
To make a class a singleton you do the following
Create a static var which is an instance of the class
Make the init function private so no other class can initialise it
Eg
class Singleton {
static var shared = Singleton()
var info = "singleton info variable"
private init() {}
func doSomething() {}
}
To access the class you do the following
Singleton.shared.doSomething()
or
let singletonInfo = Singleton.shared.info
You have two options:
(Simplified) - Either you create a new instance and pass it on:
class MyClass {
let name: String
init(name: String) { self.name = name }
}
class MyViewController: UIViewController {
let myClass = MyClass(name: "Hello World")
func actionThatCausesSegue() {
let copyOfMyClass = MyClass(name: self.myClass.name)
self.performSegueWithIdentifier(identifier: "MySegue", sender: copyOfMyClass)
}
}
Or you can use structs:
struct MyStruct {
let name: String
init(name: String) { self.name = name }
}
class MyViewController: UIViewController {
let myStruct = MyStruct(name: "Hello World")
func actionThatCausesSegue() {
// structs are always copied when passed around.
self.performSegueWithIdentifier(identifier: "MySegue", sender: self.myStruct)
}
}
Structs are always copied, when you pass them around. Here's the explanation from the Swift Programming Language Guide by Apple:
Structures and Enumerations Are Value Types
A value type is a type whose value is copied when it is assigned to a
variable or constant, or when it is passed to a function.
You’ve actually been using value types extensively throughout the
previous chapters. In fact, all of the basic types in Swift—integers,
floating-point numbers, Booleans, strings, arrays and dictionaries—are
value types, and are implemented as structures behind the scenes.
All structures and enumerations are value types in Swift.
You can read more about the differences here.
It depends on the situation, but I sometimes do this for views in iOS. For example when the data model changes you want the view to update, so I implement a method in the controller called configureThingyViewWithThingy which takes the new 'thingy' and updates the view. Then whatever mechanism you're using to monitor data model changes (KVO, notifications, etc.) will call this method to reconfigure the view with the new data.

iOS: Core Data fails to save when attribute is a double

I thought I'd ask here first before I sent my laptop flying out of the window. I am very new to iOS development and have been toying around with Core Data trying to create an expense manager app. I have a single entity named "Account" which has two non-optional attributes (name and initBalance) as follows:
I have also created an NSManagedObject subclass as follows:
//Account.swift
class Account: NSManagedObject {
override func awakeFromInsert() {
super.awakeFromInsert()
initBalance = NSNumber(double: 0.0)
name = ""
}
}
//Account+CoreDataProperties.swift
extension Account {
#NSManaged var initBalance: NSNumber
#NSManaged var name: String
}
The Account entities are presented in the AccountsViewController (a subclass of UITableViewController conforming to the NSFetchedResultsControllerDelegate protocol) using an NSFetchedResultsController. To add a new Account I use a segue from AccountsViewController to direct me to the AccountInfoViewController (shown below) which has two textFields, one for the name and one for the balance of the account. When the latter is about to disappear a new Account is inserted in the context with the name and balance derived from the textFields. Once the parent controller appears (AccountsViewController) it tries to save the changes and updates the tableView.
Now, if I insert a new Account for which the balance is an integer number life is good; the context is able to save the changes, tableView updates its rows by showing the newly inserted account, and I am happy. When I try to insert an Account for which the balance is a decimal number, the app crashes at the point where the context tries to save the changes. I get no useful error at all as to why it happens. Here is the code for the controller managing the textFields:
class AccountInfoViewController: UIViewController {
#IBOutlet weak var nameField: UITextField!
#IBOutlet weak var balanceField: UITextField!
var store: DataStore! // set by the parent viewController everytime this controller appears
let numberFormatter = MyFormatter()
// insert the new account into the context before the controller disappears
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
store.insertAccount(nameField.text!, balance: numberFormatter.numberFromString(balanceField.text!)!)
}
}
The MyFormatter is this:
func MyFormatter() -> NSNumberFormatter {
let formatter = NSNumberFormatter()
formatter.numberStyle = .DecimalStyle
formatter.minimumFractionDigits = 2
formatter.maximumFractionDigits = 2
return formatter
}
and the DataStore shown above contains a simple Core Data Stack and is responsible for inserting into the context:
// DataStore.swift
class DataStore {
let coreDataStack = CoreDataStack(modelName: "SmartMoney")
// inserts a new account into the context
func insertAccount(name: String, balance: NSNumber) -> Account {
let account = NSEntityDescription.insertNewObjectForEntityForName("Account",
inManagedObjectContext: coreDataStack.mainQueueContext) as! Account
account.name = name
account.initBalance = balance
return account
}
}
Is there any reason why the context fails to save the changes when the balanceField contains a non-integer number? Thank you for reading and please let me know if you would like me to post any other parts of the code.
I was finally able to figure out what's going on. Changing my attribute name from initBalance to startingBalance makes everything work again. In fact, changing the attribute's name to anything that does not start with new or init works just fine. I got the idea from this post.
It seems that when using ARC, your property's name should not start with the word new. It turns out that initBalance (or newBalance for that matter) produces the same issue. Hope it helps the next poor soul running in a similar problem.

It seems like each View Controller is creating a unique instance of my struct - which I don't want?

I'm creating an app in Swift 2.0 xCode7 using the Tabbed-Application template, with each screen having a separate ViewController. I have a struct to manage a variable I want to be accessed by all view controllers. I created the instance of the struct in the first view controller. I'm able to access the struct data and methods in the other views, but if update the data in one view, it doesn't change for all... It's acting as if each View Controller is creating its own instance on its own. I don't want that. I want each ViewController to share the same updated data in the struct. Does this mean that I should be creating a Singleton Pattern? Or, something else? I'm quite new at this, so thanks for your patience.
I'm not sure how exactly you access the structure but it might be that you only need to change struct to class because structs are value types so if you assign it or pass into a method it is copied whereas an instance of a class will avoid copying
Because you didn't give me any code, this is just my guess.
Structs are different from classes. The former stores values and the latter stores references. Let's look at this code:
var obj = SomethingCool()
obj.somethingCooler = 20
var obj2 = obj
obj2.somethingCooler = 10
If SomethingCool were a struct, obj.somethingCooler would still be 20 but obj2.somethingCooler would be 10. On the other hand, if SomethingCool were a class, both obj.somethingCooler and obj2.somethingCooler would be 20.
This is because the third line. The third line is VERY important. If SomethingCool were a struct, the values stored in obj will be copied to obj2. i.e. Two set of independent values would be created. If it were a class, the object that obj will also be referenced by obj2. i.e. There would still be just one object.
Now that you know the difference, I can tell you that you must have done something like the third line in your view controllers, haven't you?
To solve this problem, you can change from a struct to a class. Or you can create something like this:
public class SomeName {
static var myData: SomeTypeOfStruct {
return something
}
}
If you are so hellbent on keeping it as a struct you could do something that swift actually helps u out with.....AppDelegate!
The appdelegate.swift is a single instance object for any application. So in case you want to save a value that you need to access throughout the application or update throughtout the application, you might want to use AppDelegate.
E.g.
In FirstViewController.swift set the AppDelegate variable that you want to reflect on the remaining screens:
(UIApplication.sharedApplication().delegate as! AppDelegate).commonVariableName = NewValueYouWant;
In the SecondViewController.swift, take up that value from the AppDelegate
var updatedValue = (UIApplication.sharedApplication().delegate as! AppDelegate).commonVariableName;
Again...as #Sweeper said, you can always switch to class which is more reliable and used to achieve something like this.
It's acting as if each View Controller is creating its own instance on
its own.
It's all explained in Apple's Swift guide:
Structs:
struct Dog {
var name: String
}
var d1 = Dog(name: "Rover")
var d2 = d1
d2.name = "Sally"
print(d1.name)
print(d2.name)
--output:--
Rover
Sally
Classes:
class Cat {
var name: String = ""
}
var c1 = Cat()
c1.name = "Kitty"
var c2 = c1
c2.name = "Gerald"
print(c1.name)
print(c2.name)
--output:--
Gerald
Gerald
See the difference?

How to access a property of one class from another class?

I have one class:
class FoodListTable: UITableViewController
At the end of this class, I have a variable of the sum of numbers in an array:
var calorieTotal: Int {
return calorieNumberArray.reduce(0) { $0 + $1 }
}
I also have another class:
class Menu: Calculator { // Calculator is a class I had created earlier
In this class, I want to have a property that is the var calorieTotal: Int from class FoodListTable: UITableViewController. I have started this property:
let dividend =
How can I access the 'calorieTotal' property from the first class? I am very new to programming so please provide all the code possible. If you were wondering, I have looked for this question, but I still can't seem to figure it out?

Resources