I got a list of quotes I am trying to update every 24hrs, based on the calender.
This is what I tried so far, but I am getting error Cannot convert value of type 'Date?' to expected argument type 'TimeInterval' (aka 'Double')
let numberOfQuotes = 3
let quotes = ["quote 1", "quote 2", "quote 3"]
override func viewDidLoad() {
super.viewDidLoad()
let timer = Timer.scheduledTimer(timeInterval: TimeInterval(30),
target: self, selector: #selector(self.updateQuote), userInfo: nil, repeats: true)
}
#objc func updateQuote() {
let lastUpdate = UserDefaults.standard.object(forKey: "lastUpdate") as? Date
if lastUpdate != nil {
let date1:Date = Date() // Same you did before with timeNow variable
let date2: Date = Date(timeIntervalSince1970: lastUpdate ) // **Getting error on this line**
let calender:Calendar = Calendar.current
let components: DateComponents = calender.dateComponents([.year, .month, .day, .hour, .minute, .second], from: date1, to: date2)
if components.day! >= 1 {
UserDefaults.standard.set(Date(), forKey: "lastUpdate")
textView.text = "Hello there"
}
} else { //firstTime running
UserDefaults.standard.set(Date(), forKey: "lastUpdate")
textView.text = quotes[randomInt(min: 0,max: numberOfQuotes)]
}
}
lastUpdate is already a Date, the initializer Date(timeIntervalSince1970: is wrong and not needed anyway.
It's highly recommended to use optional bindings, and don't annotate types the compiler can infer.
if let lastUpdate = UserDefaults.standard.object(forKey: "lastUpdate") as? Date {
let date1 = Date()
let calender = Calendar.current
let components = calender.dateComponents([.year, .month, .day, .hour, .minute, .second], from: date1, to: lastUpdate)
...
let date2: Date = lastUpdate!
UPDATE:
let components: DateComponents = calender.dateComponents([.year, .month, .day, .hour, .minute, .second], from: date2, to: date1)
Related
How do I list yesterday's date in SwiftUI? It probably is a simple answer but I'm just learning to code and for some reason I can't seem to find the solution anywhere. Is it because it is too easy?
struct DateShown: View {
let datechoice: Datechoice
var body: some View {
Text(currentDate(date: Date()))
.font(.headline)
.fontWeight(.bold)
.foregroundColor(.blue)
}
func currentDate(date: Date!) -> String {
let formatter = DateFormatter()
formatter.locale = .current
formatter.dateFormat = "MMMM d, yyyy"
return date == nil ? "" : formatter.string(from: date)
}
}
I would rather use View extensions, though you also need Date formatting so I went the easier way and extended your solution. If the number at line "dayComponent.day" is positive, you go futher in time. I tested under:
swift 5
xcode 11.3.1
iOS 13.3.1 non beta
func yesterDay() -> String {
var dayComponent = DateComponents()
dayComponent.day = -1
let calendar = Calendar.current
let nextDay = calendar.date(byAdding: dayComponent, to: Date())!
let formatter = DateFormatter()
formatter.locale = .current
formatter.dateFormat = "MMMM d, yyyy"
return formatter.string(from: nextDay). //Output is "March 6, 2020
}
Usage is the same as yours:
Text(yesterDay())
Hi newBiew in JTAppleCalendar.
I follow this link for JTAppleCalendar.
https://www.youtube.com/watch?v=CQNotydm58s&index=6&list=PLpqJf39XekqyUG7dxcqGO0JNprryysv9Q
I have this Problem:
How to I show calendar when user click a button to change monthView to WeekView or from week View to month View
How to I change the calendar size programmatically for CalendarView and mainStack as they have constrains?
I believe I need to handle configureCalendar as below but how to change programmatically month view to week view vice versa.
I have a stack (Call it mainStack) which used to contain CalendarView
Layout for the Calendar view :
#IBOutlet weak var CalendarView : JTAppleCalendarView!<br/>
#IBOutlet weak var mainStack: UIStackView!<br/>
extension MyCalendar: JTAppleCalendarViewDataSource, JTAppleCalendarViewDelegate {
func configureCalendar( _ calendar:JTAppleCalendarView) -> ConfigurationParameters {
formatter.dateFormat = "yyyy MM dd"
formatter.timeZone = Calendar.current.timeZone
formatter.locale = Calendar.current.locale
let startDate = formatter.date(from: "2017 01 01")!
let endDate = formatter.date(from: "2027 12 31")!
//-- how to set these "
1) Full calendar view
let parameters = ConfigurationParameters(startDate : startDate, endDate: endDate)
return parameters
2) for week view
let parameters = ConfigurationParameters(startDate : startDate, endDate: endDate, numberOfRows:1)
return parameters
}
func calendar( _ calendar: JTAppleCalendarView, cellForItemAt date: Date, cellState: CellState, indexPath: IndexPath) -> JTAppleCell{
let cell = calendar.dequeueReusableJTAppleCell(withReuseIdentifier: "CustomCell", for: indexPath) as! CustomCell
cell.dateLabel.text = cellState.text
configureCell(cell:cell, cellState: cellState)
return cell
}
//------------ selected item
func calendar( _ calendar: JTAppleCalendarView, didSelectDate date: Date, cell:JTAppleCell?, cellState:CellState){
configureCell(cell: cell, cellState: cellState)
}
func calendar( _ calendar: JTAppleCalendarView, didDeselectDate date: Date, cell:JTAppleCell?, cellState:CellState){
configureCell(cell: cell, cellState: cellState)
}
func calendar(_ calendar: JTAppleCalendarView, didScrollToDateSegmentWith visibleDates: DateSegmentInfo) {
setupCalendarView(dateSegment: visibleDates)
}
}
Please help.
Thanks
So the plan is:
You have a variable for the number of rows.
In a monthView mode, it has 6 rows.
In a weekView mode, it has 1 row.
So when you want to change the mode you change numberOfRows and reload calendarView and scroll to the current date.
Also when you have weekView, you should use a little bit different ConfigurationParameters.
That's how I do this:
#IBAction func monthWeekModeChanged(_ sender: UISegmentedControl) {
if sender.selectedSegmentIndex == 0 {
numberOfRows = 6
} else {
numberOfRows = 1
}
calendarView.reloadData()
calendarView.scrollToDate(Date(), animateScroll: false)
}
var numberOfRows = 6
extension CalendarViewController: JTAppleCalendarViewDataSource {
func configureCalendar(_ calendar: JTAppleCalendarView) -> ConfigurationParameters {
let startDate = viewModel.formatter.date(from: "01-Jan-2019")
let endDate = viewModel.formatter.date(from: "31-Dec-2020")
if numberOfRows == 6 {
return ConfigurationParameters(startDate: startDate!, endDate: endDate!, numberOfRows: numberOfRows, firstDayOfWeek: .monday)
} else {
return ConfigurationParameters(startDate: startDate!,
endDate: endDate!,
numberOfRows: 1,
generateInDates: .forFirstMonthOnly,
generateOutDates: .off, firstDayOfWeek: .monday,
hasStrictBoundaries: false)
}
}
}
The tutorial here states just how to do this.
I cannot paste the whole thing here since the instructions are long.
Also, at the bottom of the page is the complete code in a zip file that you can play around with.
My code below works that if you manually use to datePicker to match the date and time with the users date and time it will print cool. However the code does not work as a alarm. I can set the date picker ahead of the user time and when the user time matches the date pickers timer nothing prints. I just want to be able to select a date/time using date picker and when the users eventually matches the datePickers time just print cool.
import UIKit
var dateFormatter : DateFormatter!
let datePicker2 = UIDatePicker();
let date = Date()
class ViewController: UIViewController {
#IBOutlet var dateLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let datePicker : UIDatePicker = UIDatePicker(frame: CGRect(x: 0,y: 330,width: self.view.frame.size.width,height: 220))
datePicker.datePickerMode = UIDatePickerMode.dateAndTime
self.view.addSubview(datePicker)
datePicker.addTarget(self, action: #selector(ViewController.change(_:)), for: UIControlEvents.valueChanged)
dateFormatter = DateFormatter()
dateFormatter.dateFormat = "YYYY-MM-dd hh:mm"
}
#IBAction func change(_ sender : UIDatePicker)
{
let pickerString = dateFormatter.string(from: sender.date)
let nowString = dateFormatter.string(from: Date())
dateLabel.text = pickerString
if pickerString == nowString {
print("cool")
}
}}
This is happening because your if statement is only being called when the picker moves. You need a timer that fires every second looking to see if they match. To use the method below you just need to move the pickerString and nowString up to global variables. If you don't like that you can refactor and use as you want.
var pickerString: String?
var nowString: String?
override func viewDidLoad() {
super.viewDidLoad()
let _ = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { (timer) in
if pickerString == nowString {
print("cool")
}
}
#buildSucceeded
I am doing an application which need to store the user's data in local. I read the documentation in Apple website, it covers part of the info in how to encode basic type, such as String and Int. However, when I try to encode with the [CLLocation]type, it failed. I am asking if some expert can give me any hint on how to encode such type in Swift?
Here is my code about the Model class.
import Foundation
import UIKit
import CoreLocation
import os.log
import CoreData
//route model
//store the model in the local database.
//change all the [CLLocations] to become the String inorder to store it in local.???? not willing
class Route: NSObject, NSCoding {
//MARK: Properties
var name :String
var area : String
var image: UIImage?
var date : DispatchTime
var routePoints = [CLLocation]()
var rating: Int
//MARK: Achieving paths
//static properties, belong to the
static let DocumentsDirectory = FileManager().urls(for: .documentDirectory, in: .userDomainMask).first!
static let ArchiveURL = DocumentsDirectory.appendingPathComponent("Routes")
//MARK: NSCoding
func encode(with aCoder: NSCoder) {
aCoder.encode(name, forKey: PropertyKey.name)
aCoder.encode(image, forKey: PropertyKey.image)
aCoder.encode(date, forKey: PropertyKey.date)
aCoder.encode(area, forKey: PropertyKey.area)
//unable to encode the [cllocation]
aCoder.encode(routePoints, forKey: PropertyKey.routePoints)
aCoder.encode(rating, forKey: PropertyKey.rating)
}
//should also added in the locations as one of the variable.
init?(Name: String, Area: String, Date: DispatchTime, Image: UIImage?, RoutePoints: [CLLocation], Rating: Int) {
guard (Rating >= 0) && (Rating <= 5) else {
return nil
}
self.name = Name
self.area = Area
self.image = Image
self.date = Date
self.routePoints = RoutePoints
self.rating = Rating
}
required convenience init?(coder aDecoder: NSCoder){
//this is the necessary property
//these are optional properties
let rating = aDecoder.decodeInteger(forKey: PropertyKey.rating)
guard let date = aDecoder.decodeObject(forKey: PropertyKey.date) as? DispatchTime,
let name = aDecoder.decodeObject(forKey: PropertyKey.name) as? String,
let image = aDecoder.decodeObject(forKey: PropertyKey.image) as? UIImage,
let area = aDecoder.decodeObject(forKey: PropertyKey.area) as? String,
let routePoints = aDecoder.decodeObject(forKey: PropertyKey.routePoints) as? [CLLocation] else{
print("Unable to decode")
return nil
}
self.init(Name: name, Area: area, Date: date, Image: image, RoutePoints: routePoints, Rating: rating)
}
//MARK: Types
struct PropertyKey {
static let name = "name"
static let image = "image"
static let date = "date"
static let area = "area"
static let rating = "rating"
static let routePoints = "routePoints"
}
}
Best wishes
The reason is that CLLocation can't be stored with NSCoder. You could implement a simple coder / decoder using a swift map for this type of value to basically store the locations in a dictionary.
let p1 = CLLocation(latitude: 1, longitude: 1)
let p2 = CLLocation(latitude: 2, longitude:2)
var locations = [p1, p2]
let codedArray = locations.map{ ["lat":$0.coordinate.latitude, "long":$0.coordinate.longitude] }
let decodedArray = codedArray.map{ CLLocation(latitude:$0["lat"]!, longitude:$0["long"]!) }
How can events be added to an FSCalendar in swift 3?
Implement the appropriate methods in a class adopting FSCalendarDataSource.
var datesWithEvent = ["2015-10-03", "2015-10-06", "2015-10-12", "2015-10-25"]
var datesWithMultipleEvents = ["2015-10-08", "2015-10-16", "2015-10-20", "2015-10-28"]
fileprivate lazy var dateFormatter2: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
return formatter
}()
func calendar(_ calendar: FSCalendar, numberOfEventsFor date: Date) -> Int {
let dateString = self.dateFormatter2.string(from: date)
if self.datesWithEvent.contains(dateString) {
return 1
}
if self.datesWithMultipleEvents.contains(dateString) {
return 3
}
return 0
}
Based On FsCalendar Documentation