[Swift 1] Day 10 - Code Exercise Solution


#1

Post your code solutions to the Day 10 Code Exercise here.

Share code, screenshots, or videos of your app in progress.

Did you like today’s activities?

-Paul


#2

Here is my app. I decided to add two new features in this exercise:

  • Users can take pictures to “illustrate” their events

  • Tap on the screen to change the unit of the “time left”
    (that is: tap anywhere to rotate between years / months / days and finally the time left in hh:mm:ss).

Countdown Pal’s Storyboard.

Countdown Pal’s code.

Demo:


#3

the photo linked to the event is a great idea. Well done.


#4

Anyone else have a problem with the autocomplete ? For me it’s not working only for NS* libraries…it’s really annoying as I have to type everything and it doesn’t give me suggestions…


#5

Ok, never mind that, it somehow fixed itself on it’s own :smile:
Here is my app, but please check it out and let me know if you can help.
I have tried and and it similar to the Apple stock app, so only 2 buttons that will change
depending on the situation.
Also added the LAP feature, but I feel I have made this in a very non-efficient way …way too much code. It seems as it could be completed better.

What I was thinking for the results is that it would be best to be appended to an Array and the the Array displayed in a Table View. At least I am pretty sure that’s how Apple are doing it :wink: And then on reset it just loads the start value of the array…

Also do you know if you can add scroll to the main View ? Or I have to create a new Sroll View and just work there ?
Anyway here is the app:


Code is here:


#6

+1 to the Goblin reference (I just killed some in Dragon’s Dogma :imp: )


#7

Really nice having the laps, great work. :thumbsup:


#8

Hi I am having real trouble with this exercise (like always) :sob: Can anyone give a pointer how to fix it?

I did go to stacks website and get someone to help but it uses an extension and works yet its not my code (its like getting someone else to do your homework).

//
//  ViewController.swift
//  Day 10 Time inteval app
//
//  Created by Sasha Akhavan-Zanjani on 23/03/2015.
//  Copyright (c) 2015 Sasha Akhavan-Zanjani. All rights reserved.
//

import UIKit

class ViewController: UIViewController {

  let calendar = NSCalendar.currentCalendar()
  
  // Set up date object
  var startTime: NSDate?
  var endTime: NSDate?
     
  @IBAction func toDatePickerAction(sender: UIDatePicker) {
    var DateFormatter = NSDateFormatter()
    DateFormatter.dateFormat = "dd-MM-yyyy HH:mm"
    var endTime = DateFormatter.stringFromDate(toDatePicker.date)
    self.dayYearLabel.text = endTime 
  }
   
  @IBAction func fromDatePickerAction(sender: UIDatePicker) {
    var fromDateFormatter = NSDateFormatter()
    fromDateFormatter.dateFormat = "dd-MM-yyyy HH:mm"
    var startTime = fromDateFormatter.stringFromDate(fromDatePicker.date)
    self.dayYearLabel.text = startTime 
  }

  @IBOutlet weak var toDatePicker: UIDatePicker!
  @IBOutlet weak var fromDatePicker: UIDatePicker!
  @IBOutlet weak var dayYearLabel: UILabel!
  
  override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

        dayYearLabel.text = startTime.differenceInDates(endTime)
     }

    func differenceInDates(date:NSDate) -> String {
    let seconds = startTime.timeIntervalSinceDate(endTime) // 86,399.9766479731
    let minutes = seconds / 60 // 1,439.99961079955
    let hours = minutes / 60 // 23.9999935133259
    let days = hours / 24 // 0.99999972972191
    let years = days / 365 // 0.00273972528690934
  
        if years > 0 { return "\(years) year" + { return years > 1 ? "s" : "" }() }
        if days > 0 { return "\(days) month" + { return days  > 1 ? "s" : "" }() }
        if hours  > 0 { return "\(hours) hour" + { return hours  > 1 ? "s" : "" }() }
        if minutes > 0 { return "\(minutes) minute" + { return minutes > 1 ? "s" : "" }() }
        if seconds > 0 { return "\(seconds) second" + { return seconds > 1 ? "s" : "" }() }
        return ""
    }

    override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
  }
}

#9

What problem are you having ?


#10

@sashaz any more insight, screenshots, or video will help us help you.

Can you email me about any big issues that have been affecting your ability to work on the projects?

PaulSolt@iPhoneDev.tv


#11

https://www.evernote.com/shard/s4/sh/5a84aad7-6206-42fe-a013-64c4e8e3c095/068742d9e832ad3730a0a6873445cc83

this is the error message I get. The app storyboard looks like the https://www.evernote.com/shard/s4/sh/3043622c-f95c-4021-b525-9c1b35edc44e/fba6a22811b259918ce381002705d49d

I can’t seem to get the startTime and endTime to work with the differenceInDates function on the dayYearLabel.text

Overall on the day tutorials I am taking ages on them, I just have terrible trouble knowing where to start and where to go. I thought of having the label and working backwords to a method from the output. I can do the follow tutorials quite well and understand them when you are explaining it but when left on my own Im a bit lost on where to go.


#12

Hi Paul and others,

I could use some feedback on this exercise, I have to admit that I was really struggling with this exercise. I could follow the code Paul wrote in the video pretty well but when I then start with an empty project all of a sudden I don’t know what to do anymore :frowning:

Anyway, I didn’t want to skip this exercise since I do understand the meaning of these exercises and that is to at least be trying to fix things yourself.

Well I did manage to get the application up and running ( I think) but I don’t know if I achieved it in the right way, so any feedback is really appreciated.

I will put the code below as well but in general what I did was to create a function which calculates seconds into years, days, hours, minutes and seconds and return these. Then I only added a create timer (copied it from the stopWatch application) under the datePicker action, the timer runs a function called updateTimer and in here it picks the chosen date and current date. then calculates the time difference between those and finally runs the function secondsToYearsDaysHoursMinutesSeconds (by converting the timeInterval into an Int).

Then I update the labels with the commands:

    yearsAndDaysLabel.text = "\(date.0) Years \(date.1) Days"
    hoursLabel.text = "\(date.2):\(date.3):\(date.4)"

I know that I did not build in any checks so the safety reward of this app will be probably 0 :slight_smile: but I just wanted to at least put all my effort into trying to get the end result which I think (hope) did manage, although I did not use all the mentioned classes.

//
// ViewController.swift
// Event Countdown Timer
//
// Created by Nico van der Linden on 15/06/15.
// Copyright © 2015 Noki-Online. All rights reserved.
//

import UIKit

class ViewController: UIViewController {

@IBOutlet weak var datePicker: UIDatePicker!
@IBOutlet weak var yearsAndDaysLabel: UILabel!
@IBOutlet weak var hoursLabel: UILabel!

var currentDate: NSDate?
var chosenDate: NSDate?
var timer: NSTimer?

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    println(datePicker.date)
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

func secondsToYearsDaysHoursMinutesSeconds (seconds: Int) -> (Int, Int, Int, Int, Int) {
    return (seconds / 365 / 3600 / 24, (seconds / (3600 * 24)) % 365, (seconds / 3600) % 24, (seconds / 60) % 60, (seconds % 60))
}

func updateTimer(myTimer: NSTimer) {
    chosenDate = datePicker.date
    currentDate = NSDate()
    
    var timeDifference = chosenDate?.timeIntervalSinceDate(currentDate!)
    var date = secondsToYearsDaysHoursMinutesSeconds(Int(timeDifference!))
    
    yearsAndDaysLabel.text = "\(date.0) Years \(date.1) Days"
    hoursLabel.text = "\(date.2):\(date.3):\(date.4)"
    
}


@IBAction func newDateChosen(sender: AnyObject) {
    
    timer = NSTimer.scheduledTimerWithTimeInterval(0.01, target: self, selector: Selector("updateTimer:"), userInfo: nil, repeats: true)

}

}


#13

@nicolinden Good start!

It would be safer to use the NSCalendar, NSDateComponents, and NSDate to do your date logic – since it’ll factor in all kinds of changes in the calendar system – along with leap years.

Some of the concepts here may help: http://oleb.net/blog/2011/11/working-with-date-and-time-in-cocoa-part-1/


#14

Hi Paul,

it took some time before I looked back at this application but since I started over with some of the examples I also looked into this one again. I have put some time in better understanding the auto layout. So I rewrote first the stopWatch application itself

Only thing I might to add in the future is the possibility to show lap times but for now that is maybe a step too far for me. But any suggestions on the type of code component I should use for that is more than welcome :wink:

I also looked at your suggestions from my past effort on the event countdown application. I rewrote it and I needed a lot of sources on the internet before I started to understand the data components and calendar. Actually most important help I got was from some guy called Paul Solt on youtube who explained an app called “How many days old are you” :smiley:

However, although my app is working this way, I don’t believe I wrote it efficient. It would be great if you can help me out here? I also noticed that for some future exercises you added the solution on the exercise forum as well. It would be really helpful if you could do that for this one (and other day exercises) as well. This way there is always some code example you can fall back to in case you get stuck? The examples wouldn’t need any advanced stuff or formatting but just a simple example on how to achieve the end result?

//
// ViewController.swift
// Countdown
//
// Created by Nico van der Linden on 27/07/15.
// Copyright © 2015 Noki-Online. All rights reserved.
//

import UIKit

class ViewController: UIViewController {

let calendar = NSCalendar.currentCalendar()
var date: NSDate?
var timer: NSTimer?
var currentDate: NSDate?

@IBOutlet weak var datePicker: UIDatePicker!
@IBOutlet weak var yearDayLabel: UILabel!
@IBOutlet weak var hourMinutesSecondsLabel: UILabel!

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
}

override func preferredStatusBarStyle() -> UIStatusBarStyle {
    return UIStatusBarStyle.LightContent
}

func updateTimer(timer: NSTimer) {
    var dateFormatter = NSDateFormatter()
    dateFormatter.dateFormat = "HH:mm:ss.SS"
    currentDate = NSDate()
    
    var components = NSCalendarUnit.CalendarUnitYear | NSCalendarUnit.CalendarUnitDay | NSCalendarUnit.CalendarUnitHour | NSCalendarUnit.CalendarUnitMinute | NSCalendarUnit.CalendarUnitSecond | NSCalendarUnit.CalendarUnitNanosecond
    var dateComponent = calendar.components(components, fromDate: currentDate!, toDate: datePicker.date, options: nil)

    var numberOfYears = dateComponent.year
    var numberOfDays = dateComponent.day
    var numberOfHours = dateComponent.hour
    var numberofMinutes = dateComponent.minute
    var numberOfSeconds = dateComponent.second
    var numberOfNanoSeconds = dateComponent.nanosecond
    
    yearDayLabel.text = "\(numberOfYears) years, \(numberOfDays) days"
    hourMinutesSecondsLabel.text = "\(numberOfHours):\(numberofMinutes):\(numberOfSeconds)"
    
}

@IBAction func datePickerChanged(sender: UIDatePicker) {
    println("value changed")
    
    if timer == nil {
        timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "updateTimer:", userInfo: nil, repeats: true)
    }
    
    date = NSDate()
    
}

}

Kind Regards,
Nico van der Linden


#15

Great work!

You’d need to use a UITableView to display a list of elements from an Array.

One of the later lessons shows how to work with TableView around Day 24/25 using photos + text.

Yea, solution code would be helpful – I’ll make sure to keep that in mind as I work on new materials.


#16

ViewController from the Countdown Event App

https://github.com/smuet007/iOS-Apps.git


#17

This’s my Github Link
ViewController From The Countdown Timer App:
import UIKit

class ViewController: UIViewController {
    @IBOutlet weak var datePicker: UIDatePicker!

    @IBOutlet weak var yearMonthDayLabel: UILabel!
    @IBOutlet weak var timeLabel: UILabel!
    
    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 datePickerSrolled(sender: AnyObject) {
        _ = NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: "updateTimer", userInfo: nil, repeats: true)
    }
    func updateTimer(){
        let date = fromDateToDate(datePicker.date)
        yearMonthDayLabel.text = "\(date.year)years  \(date.month)month  \(date.day)days"
        timeLabel.text = "\(date.hour):\(date.minute):\(date.second)"
    }
   
    func fromDateToDate(day : NSDate) -> NSDateComponents{
        let date = NSDate()
        let unitFlags: NSCalendarUnit = [.Second,.Minute,.Hour, .Day, .Month, .Year]
        let component = NSCalendar.currentCalendar().components(unitFlags, fromDate: date, toDate: day, options: NSCalendarOptions.WrapComponents)
        return component
    }
}

#18

You didn’t upload the entire code folder into GitHub. I can’t run the project, but I did see the screenshots.

For screenshots you’ll want to reduce them in size (don’t use the iPhone 6S +) and you’ll probably want to cut pixels in half (due to retina). For web like GitHub, displaying non-retina generally works best for viewing. (divide width or height in two: i.e.: 800x400 becomes 400x200)

Command + S will save screenshots from the Simulator to your desktop.

Fix: Go up one directory in Finder and re-add it to github with the .xcodeproj file and any top level files.


#19

Thank PaulSolt so much. I did repair my code folder into GitHub.
Here is my GitHub Link


#20

Great work @phamngocquynh !

  1. Try and see if you can use some if/else logic to properly display plural versus singular.
    0 seconds
    1 second
    2 seconds
    0 years
    1 year
    2 years
    etc.

  2. Try to display time in the past as well. Right now it shows up negative. You can use the negative value to trigger logic that will correctly display the count moving into the future.

  3. Try increasing the font size of the time label (play with different fonts)

Have fun!

Great work with GitHub!