Swift - Declare a global NSDate without value - swift

I want to create a global NSDate in my app, because I want to save the date of the first time ever the app has been opened in this variable. I wrote
"var LaunchDate = NSDate()" before the declaration of the main class of the first view controller, and in the viewdidload, if it is the first time the app is opened, it saves the date into the global variable LaunchDate. But everytime I open the app, it saves the current date because of "var LaunchDate = NSDate()".
I didn't find a solution, do you have any idea to declare a global date without that he gives the current date please?

You could use NSUserDefaults to store the value.
The code checks if a value exists.
If yes it reads the value, if no it writes the current date.
var launchDate : NSDate!
let defaults = NSUserDefaults.standardUserDefaults()
if let dateOfFirstLaunch = defaults.objectForKey("dateOfFirstLaunch") as? NSDate {
launchDate = dateOfFirstLaunch
} else {
let currentDate = NSDate()
defaults.setObject(currentDate, forKey:"dateOfFirstLaunch")
launchDate = currentDate
}

Global variables are variables that are defined outside of any
function, method, closure, or type context
struct globalDate
{
static var LaunchDate = NSDate()
}
In swift if you encapsulate the variable in struct, you can access that in any classes.
Document
Global Variable

Try this:
override func viewDidLoad() {
var LaunchDate: NSDate
// when you want to set the value for it:
LaunchDate = NSDate()
}
The Proble, is that NSDate() which you tried to do is a function, which gets back a value of the current date.

I would use the Singleton Pattern with NSUserDefaults.
The code should be something like this
import Foundation
class UserDefaults {
static let sharedInstance = UserDefaults()
var launchDate: NSDate? {
get {
return NSUserDefaults.standardUserDefaults().objectForKey("launch_date") as? NSDate
}
set {
NSUserDefaults.standardUserDefaults().setObject(newValue, forKey: "launch_date")
}
}
}
Access it using this code
UserDefaults.sharedInstance.launchDate

Related

Saving Date in UserDefaults of the first time the App was opened

I am trying to set the Date() the very first time an App is opened. This will be set in UserDefaults.
I used register() to save the date in UserDefault. The problem is.. this value seems to be saving on every launch, which defeats the purpose of UserDefaults.register.
Here is my code:
let initialOpen: NSDictionary = ["FirstOpen" : Date()]
UserDefaults.standard.register(defaults: initialOpen as! [String : AnyObject])
let firstOpenDate = UserDefaults.standard.value(forKey: "FirstOpen")
print("First Opened: \(firstOpenDate)")
I am calling this within didFinishLaunchingWithOptions.
How can I record the time that the App is launched for the first time in UserDefaults?
There's no need for register(defaults:).
Don't use value(forKey:) to read data from UserDefaults.
All you need to do is first check if the date has been set, if not, set it.
if let firstOpen = UserDefaults.standard.object(forKey: "FirstOpen") as? Date {
print("The app was first opened on \(firstOpen)")
} else {
// This is the first launch
UserDefaults.standard.set(Date(), forKey: "FirstOpen")
}

Using the Same Currency Formatting in Multiple Methods

I'm using some currency formatting to set currency symbols/styles to the user's local settings. Here is my code. I think it works fine. It is located in my viewDidLoad.
let currencyFormat = NumberFormatter()
currencyFormat.locale = NSLocale.current
currencyFormat.usesGroupingSeparator = true
currencyFormat.numberStyle = NumberFormatter.Style.currency
...
labelTotalAmount.text = currencyFormat.string(for: totalAmount)
The trouble is, I want to use this same formatting in two other different Methods. It seems to be a waste to repeat the formatting for each method whenever I want to do formatting.
Is there a way to set the formatting once and have it remember the settings in every method of the class?
I'm using Swift 3. I appreciate any help you can give!!
Make it a computed property of the class:
class Whatever {
let currencyFormat: NumberFormatter = {
let res = NumberFormatter()
res.numberStyle = .currency
res.usesGroupingSeparator = true
return res
}()
}
Now you can use that property in any method.
func someMethod() {
let str = currencyFormat.string(for: 5.99)
}

Get variable value or run function from different Object - Swift

I am trying to: get the value of a few variables, as well as run some functions which live in Object A, all from Object B.
I have tried for hours now to make it work with delegates and protocols. No luck.
I can't do something like this:
var delegate: MyDelegate = ViewController()
Because it seems to create a new instance of ViewController. And I want the values from the instance that is already running.
I also cannot do:
var delegate: MyDelegate?
Because the ViewController object never responds. So I get a nil anytime I call delegate?.somefunction()
I don't want a segue between screens. I just need to start a function from another object.
I bet this is an easy fix. I just can't get it. Thanks for your help.
Some of my code:
class PauseButtonView: NSView{
var delegate: PauseButtonDelegate?
...
var result = delegate?.startFunction()
}
protocol PauseButtonDelegate {
func startFunction() -> String
}
class ViewController: NSViewController, PauseButtonDelegate {
func startFunction() -> String {
let myString = "Hello World!"
return myString
}
}
If you don't want either classes to have a reference to the other, you could use internal notifications to communicate between them:
// in your PauseButtonView
let object:[String:AnyObject] = [ "aParameter" : 42 ]
let startNotification = NSNotification(name: "startFunction:", object: object)
NSNotificationCenter.defaultCenter().postNotification(startNotification)
// in the view controller
func startFunction(notification:NSNotification)
{
let object = notification.object as? [String:AnyObject]
//...
}

Swift NSDate Extension Error: Mutating isn't valid on methods in classes or class-bound protocols

I am trying to extending NSDate but am getting two errors :
extension NSDate { //'mutating' isn't valid on methods in classes or class-bound protocols
mutating func addMonth() {
let calendar = NSCalendar.currentCalendar()
let component = NSDateComponents()
component.month = 1
self = calendar.dateByAddingComponents(component, toDate: self, options: []) //Cannot assign to value: 'self' is immutable
}
}
My guess is that NSDate is a class and not a Swift type and as the error states mutating is not possible on methods in classes. If I return the value and assign it everything works but I want to know the exact reason this is not working and if there is a better workaround.
NSDate objects encapsulate a single point in time, independent of any particular calendrical system or time zone. Date objects are immutable, representing an invariant time interval relative to an absolute reference date (00:00:00 UTC on 1 January 2001).
NSDate Documentation
Because NSDate objects are immutable, you can't arbitrarily add a month to one. You could modify your extension to return a new NSDate object from an existing date, with a month added:
extension NSDate {
func addMonth() -> NSDate? {
let calendar = NSCalendar.currentCalendar()
let component = NSDateComponents()
component.month = 1
let newDate = calendar.dateByAddingComponents(component, toDate: self, options: [])
return newDate
}
}

Time difference between button presses swift

Right now I'm working on a time clock app that allows the user to punch in/out of work time. But I'm having trouble figuring out how to make that function possible.
In my model I have:
struct TimeLog {
var punchInTime: CFAbsoluteTime
var punchOutTime: CFAbsoluteTime
var timeWorked: Double
init (pInTime: CFAbsoluteTime, pOutTime: CFAbsoluteTime) {
self.punchInTime = pInTime
self.punchOutTime = pOutTime
self.timeWorked = pOutTime - pInTime
}
}
And in my view controller:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func punchInButtonPressed(sender: AnyObject) {
// not sure what actions are needed here to start the "aTimeLog" variable
}
#IBAction func punchOutButtonPressed(sender: AnyObject) {
// not sure what actions are needed here to complete the "aTimeLog" variable
}
I'm trying to complete this variable:
var aTimeLog = TimeLog(pInTime: //get the punch in time here, pOutTime: //get the punch out time here)
And once the variable "aTimeLog" is complete (the punchOutButton is pressed) I want to display a log of all of my "timeWorked" variables.
Forgive me in advance. You might be able to tell I'm just learning programming and Swift.
Personally, I'd keep a variable in NSUserDefaults - storing the punch in time. Then, when the punch out button is tapped, it fetches the dateTime variable from NSUserDefaults, does the needed calculation and returns the result. This caters for if a user closes the app (punch in time is remembered).
This creates an NSUserDefaults object
var punchInTime : NSUserDefaults = NSUserDefaults.standardUserDefaults()
#IBAction func punchInButtonPressed(sender: AnyObject) {
Saves the current time
punchInTime.setObject(NSDate(), forKey: "punchInTime")
punchInTime.synchronize()
}
#IBAction func punchOutButtonPressed(sender: AnyObject) {
fetches the saved time
punchInTime.objectForKey("punchInTime") as NSDate
creates a variable holding the current time so you can compare the two
var currentTime : NSDate = NSDate()
currentTime.timeIntervalSinceDate(punchInTime) // returns seconds
Now you can save the start time, end time and total working time inside, say, a dictionary with the key as the date maybe...
}
Then when you want to display all the days worked, simply loop through the dictionary :)
...hope I understood correctly
As one of the possible solutions, you could alter your init method as follows:
initWithStartTime (pInTime: CFAbsoluteTime)
{
self.punchInTime = pInTime
}
Then add a method like:
func workedTimeWithEndTime(pOutTime: CFAbsoluteTime) -> CFAbsoluteTime
{
return pOutTime - self.punchInTime
}
Finally you'll probably want to add "var timeLog: TimeLog!" into your view controller and initialise it in punchInButtonPressed with start time.
You should give your ViewController class a ref to a TimeLog class (why did you choose a struct? works too but just curious).
var timeLog: TimeLog?
Second of all you want to initialise it with a fresh one every time you punch in
#IBAction func punchInButtonPressed(sender: AnyObject) {
let now = CFAbsoluteTimeGetCurrent()
self.timeLog = TimeLog(pInTime: now)
}
So you initialise only with the pInTime, and the rest of the times are set to 0 / null. Next when you punch out you add the pOutTime and you can calculate the timeWorked.
#IBAction func punchOutButtonPressed(sender: AnyObject) {
if (self.timeLog == nil) {
return
}
self.timeLog!.punchOut(CFAbsoluteTimeGetCurrent());
println(self.timeLog!.timeWorked)
}
Since we don't use the constructor like you've created it and it needs a new function we need to change your class (use class unless you know why you want a struct).
class TimeLog {
var punchInTime: CFAbsoluteTime
var punchOutTime: CFAbsoluteTime
var timeWorked: Double
init (pInTime: CFAbsoluteTime) {
self.punchInTime = pInTime
self.punchOutTime = 0
self.timeWorked = 0
}
func punchOut(pOutTime: CFAbsoluteTime) {
self.punchOutTime = pOutTime
self.timeWorked = self.punchOutTime - self.punchInTime
}
}
Try this:
// run this on first action/tap
let start = Date()
// then, run this on the second time/interaction, to get the negative elapsed time
// for example: for 0.8 seconds this will return -0.8694559335708618
print("Elapsed time: \(start.timeIntervalSinceNow) seconds")