I am developing an iOS application where I want to record the time when a user presses a particular button and keep it. Later I will use this time record in background. Is there a nice way of doing that without invoking NSUserDefaults or CoreData or whatever other database?
I am very new to iOS development. I think this is very likely to be a naive question. But I'm just curious. Please don't laugh at me haha.
Edit: This is indeed a very naive question haha.
A simple way to make sure your data is available everywhere in your app and only persists for each app session would be to use a singleton. Something like this.
// Create a class to store the data
class SessionData : NSObject {
// Create a shared instance of your class
static let sharedInstance = SessionData()
// Create a variable to store the date object
var timeStore:NSDate?
}
This will mean that anywhere in your app you can get and set this data as below.
// Get
if let time = SessionData.sharedInstance.timeStore {
println(time)
}
// Set
SessionData.sharedInstance.timeStore = NSDate()
It is worth mentioning that despite the above being a valid method, You may be able to avoid doing this by re-thinking your app structure and passing data between classes instead. You should have a look at Delegation.
Also as #CouchDeveloper mentions in their comment below, you may want to included a dispatch queue to prevent crashes or locks in the situation where two or more classes try to read and or write data at the same time.
Related
In an app that I am working for, I need array variable that can be used in all UIViews. Currently when the array is changed in a view it is stored in the database, and when I need the updated version of the array in the previous view, I use the viewWillAppear method and retrieve the updated array from the database. While going to another view by a segue, I use the passing data by prepareForSegue, but if I use the back button, or just change the screens via tab bar, I use the viewWillAppear and a query.
Is there any way that when the array is created in a view, the data in it will be accessible in all views?
As I've stated in my comment, singletons are generally frowned upon for a myriad of reasons. However, there is much debate on this topic:
What is so bad about singletons?
Having said that, the best way I know to make a variable globally available for the session is by creating a singleton.
struct myArray {
static var data: [Int] = []
}
You could set this singleton up to fetch the records using CoreData and store the current working version in a static variable for quick access.
note: I am really very curious to see some other approaches.
Singleton
Singleton is basically a global variable that you can use them in any views, but some developers experience some bugs and difficulties, use it at your own risk, I recommend this method when you're definite that you will use that data a lot (STILL RISKY), but this method is like goddess of data handling :).
Create a NSObject subclass and call it DataManager.swift (I call it data manager cause it handle data.) as following:
import UIKit
class DataManager: NSObject {
//Store Data Globally
static var someData: NSArray! //This Boolean, you can choose whatever you want.
}
the static is what keep your data live.
Now you can store and receive someData from anywhere like you handle any data type like this.
//Store
DataManager.someData = []
//Receive
print(DataManager.someData)
This seems like a very simple question, but I can't find a clear answer. Also it's not specifically about swift or iOs, but I'm new to programming and swift is the only language I know anything about, so I don't know how to phrase it for a more general context.
I'm trying to write an iOs app and I found myself defining the same constants many times throughout my code.
I must have written this line about a hundred times, for instance:
let calendar = NSCalendar.currentCalendar()
Another example is getting my only User object from its persistent store:
let realm = try! Realm()
let user = realm.objects(User).first!
I define those calendar and user constants over and over throughout my whole code in classes and subclasses and extensions and computed properties.
That seems kind of stupid, though. I think I should be able to define calendar once and for all and just use it when I need it. So my first thought was to declare a global constant, but apparently everybody thinks anything with the word "global" in it should be avoided at all costs.
So what should I do? Is there another solution for this? Should I just keep writing the same stuff over and over again?
Thanks in advance,
Daniel
There are many different situations in which the best use of different approaches.
For example in your case:
let calendar = NSCalendar.currentCalendar()
currentCalendar is a static method that already returns a pointer to the object that you will use. And you don't need to set it to some constant for using with simple case:
print(NSCalendar.currentCalendar().calendarIdentifier)
Another thing that is most often better to use a shorter name for the object in your code when you need to refer to it often and this code looks much more readable:
print(calendar.calendarIdentifier)
If you have the functionality that you will often use in application from different places, you can just make it to the static method and does not create an object of this class every time you call it:
class NetworkConnection {
class func getDataFromServet(completion block: (data: SomeType) -> Void) {
...
}
}
And use it without object creation like:
NetworkConnection.getDataFromServer(completion: {(data: SomeType) -> Void in
...
})
If you need to use created object in many places, the best solution is not to make it global or singleton instance, but pass a pointer to it to the objects where you need to use it. This makes the code more readable, for example by looking at the input parameters of the init method, anyone can immediately understand which objects use this class for their work. And this class is easier to take from the project in a separate module and connect to another project. At that time, if you use the singleton instance, the class's interface is not clear what it can be used and this leads to code obfuscation. This applies and to the global objects.
If you're constantly changing it, why aren't you just using var instead of let?
New to iOS development and trying to develop my app with correct practices. My main issue is trying to figure out the best way to store a bunch of simple data globally.
The app connects to a computer adhoc wifi and gathers information about the current state. (ex// gpu temp, computer name, display resolution, date/time, etc). The various view controllers I have then allow the user to adjust some of these settings so I want to be able to keep track of these changes across all view controllers.
I have been wrestling between using a plist, core data, or singleton class to store all the information. Since the user will be connected to one computer for the life of the app I am leaning towards singleton since it seems easiest to get and set data. However, I have read that using a singleton is really not the best practice for various reasons. I have read up on plists and core data a little and seems like a decent amount of work just to get and set values. Should I spend the time using those or would some other method be a better way to accomplish all of this.
Update:
After both answers from Aaoli and Swift Rabbit. I wanted to clarify for my use case that the data I am storing did not need to be "saved" when the app was closed. So if you are coming to this question and need to store your data even if the app closes look at #SwiftRabbit's answer.
To use Global variable in Swift you need to define struct outside the class and because you don't need the variable to be swimming in the whole app memory without binding:
struct GlobalVar {
static var myvar = 0
}
To use simply the global variable from anywhere use :
GlobalVar.myvar = 10
In my case, using "simple" data, which is not sensitive, I usually use the user defaults. They can be accessed globally through the project. For example, it can be set this way :
var prefs:NSUserDefaults = NSUserDefaults.standardUserDefaults()
prefs.setObject(myValue, forKey: "myKey") // myValue is of type typeOfValue
prefs.synchronize()
It can be accessed this way :
var prefs:NSUserDefaults = NSUserDefaults.standardUserDefaults()
prefs.valueForKey("myKey") as? typeOfValue
Using setObject can be used for any kind of value, that's why I cast it when retrieving it from the userDefaults. You could actually use other methods to insert it and retrieve it that would make your task easier. For example, you could tell you are inserting a bool with :
prefs.setBool(<#value: Bool#>, forKey: <#String#>)
And specify you are retrieving one with :
prefs.boolForKey(<#defaultName: String#>)
All methods can be found in the apple documentation here
My opinion: create a singleton, e.g. in this way:
class MyClass {
/// The singleton instance
private static var singletonInstance: MyClass!
class var sharedInstance: MyClass! {
get {
singletonInstance = singletonInstance ?? MyClass()
return singletonInstance
}
}
private init() { }
}
Or in this way:
class MySingletonClass {
static let sharedInstance = MySingletonClass()
private init() {
}
Many people consider Singleton a poor design pattern, but in my opinion it is not. It is good to have a pattern which ensures that a piece of information is only available once. What is not good is to have global access to this Singleton from anywhere in the application. Some people counter-act this with "Dependency Injection", which basically means that your classes does not "pull" the information from the Singleton but the information is "pushed" into the class from (some other instance) outside. This promotes loose coupling and better test-ability. But this is an advanced topic which needs much more information. (Google "typhoon framework" for iOS if you are interested in this)
I have a class, User, that has an NSMutableArray that stores custom NSObjects. I only want one of these to ever be instantiated throughout the entire app, and I would like to be able to call methods on it in each ViewController for getting and setting. My problem is that I don't know how to call the methods so they apply to this one instance, instead of creating a new one each time. I'm new to objective-c, so the learning curve makes me feel I'm missing something a bit obvious. I've been working on this all day and am at a wit's end. Is there a good solution to my dilemma? Should I use a singleton class?
(If it helps, the class User is basically a class that stores a to-do list for each user that uses my app. The custom NSObjects are to-do items. There's probably a better storage method that should be used here, but I'm not sure what it is.)
RandomPleb it sounds like what you're looking for is a Singleton. http://en.wikipedia.org/wiki/Singleton_pattern. I also think this question has been answered before so search around on SO.
Laymen's terms; you create a static reference to the class that you only want one of inside that class, then make a static method in the following way:
//call this from classes that want to modify it
public static getsharedinstance()
{
if(the static instance of this class does not exist){
instantiate instance;
}
return this classes static instance..
}
Hope this helps (and if this is wrong, I hope someone can correct me)
Also in regards to your storing objects, I think NSMutableArray is fine unless it is a very big persistent list where each task has many properties in which case maybe using CoreData would be better.
Fenix
I have been looking at Swift the last couple of days and it looks good, I am confused on a point though even after review of the guide Apple published.
I understand that memory management in Swift uses ARC and therefore quite safe, however in situations where I'd like more fine grained control of object creation and destruction I'm slightly confused.
Take these two simple examples:
In ObjC, when you'd (for example) like a UIViewController you intend to push to stay around for the lifetime of your app and only be created once (say because it's expensive to create), you'd make it a property and then wrap it's Alloc Init like this:
if (!self.myProperty)
{
self.myProperty = [[MyObj alloc] init];
}
This way it only creates once, keeps state and the same object instance can be reused indefinitely, yielding known object references, and good performance not having to recreate each time the viewController goes out of scope.
Another example of this is with NSMutableString, vs Swifts String.
You can set an NSMutableString's string many times and it will keep the same object reference, however this doesn't seem to be the case with a Swift String when changing it.
This may just be 'deprecated thinking in Objective C' but is there a best practice with regard to keeping around expensive objects or to keep state (same object) for certain objects during the lifetime of their usage.
I think what you're looking for is a "Lazy stored property":
The example in the swift docs is:
class DataManager {
#lazy var importer = DataImporter()
var data = String[]()
// the DataManager class would provide data management functionality here
}
and it says about #lazy:
A lazy stored property is a property whose initial value is not calculated until the first time it is used. You indicate a lazy stored property by writing the #lazy attribute before its declaration.
The comment about NSMutableString is a little different, you can continue to use NSMutableString in your swift code, but Apple are encouraging developers to use the Swift built-in types whenever possible :)
see the "String Mutability" section in the swift docs