Reputation: 75
I'm having trouble with storing a date that I got from SQLite DB into a Date
Var, I'm trying to save the date coming from DB to the ResultTask.AlarmDate
after converting it from String to Date.
When I tried and deleted the ?
from ResultTask.AlarmDate?
it stored the data fine, but when I have a task without an alarm I get an error cause I want to store nil
it the var when there's no alarm, and tried multiple other ways to fix it but nothing work.
I made a break point right after the issue and used the Console
to see the data and got confused, cause the data shown when I print what I'm trying to store in the var but the var is still nil
, all shown below.
Notes
The code that getting data from DB works fine, I'm using the Objective-C FM-Database library, and result is seen in the Console
below.
the .toDate()
is an extension for String
that I use and it code is in AppDelegate.swift
as seen bellow, and it work just fine.
the Task
Variable type is something I made in a Task.swift
file to easy the work, and it work just fine & shown below.
The Function:
func GetTasks() -> [Task]{
var Tasks : [Task] = [Task]()
let dirPaths = NSSearchPathForDirectoriesInDomains(.documentDirectory,.userDomainMask, true)
let docsDir = dirPaths[0]
databasePath = (docsDir + "/" + "Tasks.db") as NSString
let TaskRecorderDB = FMDatabase(path: databasePath as String)
if (TaskRecorderDB?.open())! {
let querySQL = "Select * from 'Tasks' ORDER BY Priority DESC"
let results:FMResultSet? = TaskRecorderDB?.executeQuery(querySQL, withArgumentsIn: nil)
while results!.next() {
var ResultTask : Task! = Task()
ResultTask.ID = Int((results?.int(forColumn: "ID"))!)
ResultTask.FileName = results?.string(forColumn: "FileName")
ResultTask.Name = results?.string(forColumn: "Name")
ResultTask.Categorie = Int((results?.int(forColumn: "Categorie"))!)
ResultTask.Priority = Int((results?.int(forColumn: "Priority"))!)
ResultTask.AlarmDate? = (results?.string(forColumn: "Alarm").toDate())!
//Break point
ResultTask.Repeat? = (results?.string(forColumn: "Repeat"))!
ResultTask.Completed = Int((results?.int(forColumn: "Completed"))!).toBool()
if(ResultTask.Completed == false){
Tasks.append(ResultTask)
}
ResultTask = nil
}
TaskRecorderDB?.close()
} else {
print("Error #DB06: \(TaskRecorderDB?.lastErrorMessage())")
}
return Tasks
}
Console:
(lldb) print (results?.string(forColumn: "Alarm").toDate())!
(Date) $R0 = 2016-11-23 17:21:00 UTC
(lldb) print ResultTask.AlarmDate
(Date?) $R1 = nil
(lldb)
AppDelegate.swift:
extension String {
func toDate () ->Date! {
var FinalDate : Date! = nil
if (self != ""){
let DateFormatter : Foundation.DateFormatter = Foundation.DateFormatter()
DateFormatter.locale = Locale.current
DateFormatter.dateFormat = "y-MM-dd_HH-mm-ss"
FinalDate = DateFormatter.date(from: self)!
}
return FinalDate
}
}
Task.swift:
import Foundation
class Task : NSObject {
var ID : Int! = nil
var FileName : String! = nil
var Name : String! = nil
var Categorie : Int! = nil
var Priority : Int! = nil
var AlarmDate : Date! = nil
var Repeat : String! = nil
var Expired : Bool! = nil
var Completed : Bool! = nil
}
Thanks in advance.
Edit for @KaraBenNemsi :
I updates the .toDate()
as you said.
& in task I used var AlarmDate : Date?
instead of var AlarmDate : Date! = nil
(I didn't use you're other tip in Task.swift
for now cause I'll need to change a lot of other code in the app).
And used ResultTask.AlarmDate = results?.string(forColumn: "Alarm").toDate()
and I get a fatal error: unexpectedly found nil while unwrapping an Optional value
in it when the task doesn't have an alarm.
Upvotes: 0
Views: 233
Reputation: 2774
Try to change this line in the task class since it can be optional
from this
var AlarmDate: Date! = nil
to this
var AlarmDate: Date?
And then use this line to set the alarm
ResultTask.AlarmDate = results?.string(forColumn: "Alarm")?.toDate()
Also variable names should usually start with a lowercase letter.
I also think this line is unnecessary. You can just omit that line.
ResultTask = nil
Please also change the extension to
extension String {
func toDate() -> Date? {
guard self != "" else {
return nil
}
var finalDate: Date?
let DateFormatter : Foundation.DateFormatter = Foundation.DateFormatter()
DateFormatter.locale = Locale.current
DateFormatter.dateFormat = "y-MM-dd_HH-mm-ss"
finalDate = DateFormatter.date(from: self)
return finalDate
}
}
And maybe try to get more into how optionals work https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html
Addition: Your class task should probably also look more like below. But then you have to change code in other places as well. It also forces you to pass all the required parameters in the constructor when initialising the task object.
class Task {
var id: Int
var fileName: String
var name: String
var category: Int
var priority: Int
var alarmDate: Date?
var repeating: String
var expired: Bool
var completed: Bool
init(id: Int, fileName: String, name: String, category: Int, priority: Int, repeating: String, expired: Bool, completed: Bool) {
self.id = id
self.fileName = fileName
self.name = name
self.category = category
self.priority = priority
self.repeating = repeating
self.expired = expired
self.completed = completed
}
}
And here is also a link to a Swift style guide:
https://github.com/raywenderlich/swift-style-guide
Upvotes: 2
Reputation:
Change your task to have this
var AlarmDate : Date?
And then do this
if let alarm = results?.string(forColumn: "Alarm").toDate() {
ResultTask.AlarmDate = alarm
}
If any nil is found while unwrapping results, you won't set the value of ResultTask.AlarmDate.
Upvotes: 0