I am learning to use predicates for filtering. I found a tutorial, but one aspect is not working for me in Swift 3. Here is some specific code:
let ageIs33Predicate01 = NSPredicate(format: "age = 33") //THIS WORKS
let ageIs33Predicate02 = NSPredicate(format: "%K = 33", "age") //THIS WORKS
let ageIs33Predicate03 = NSPredicate(format: "%K = %#", "age","33") //THIS DOESN'T WORK
let ageIs33Predicate04 = NSPredicate(format: "age = %#","33") //THIS DOESN'T WORK
All 4 compile, but the last 2 produce no results even though I have a case where age = 33. Here is the test complete test code from the tutorial:
import Foundation
class Person: NSObject {
let firstName: String
let lastName: String
let age: Int
init(firstName: String, lastName: String, age: Int) {
self.firstName = firstName
self.lastName = lastName
self.age = age
}
override var description: String {
return "\(firstName) \(lastName)"
}
}
let alice = Person(firstName: "Alice", lastName: "Smith", age: 24)
let bob = Person(firstName: "Bob", lastName: "Jones", age: 27)
let charlie = Person(firstName: "Charlie", lastName: "Smith", age: 33)
let quentin = Person(firstName: "Quentin", lastName: "Alberts", age: 31)
let people = [alice, bob, charlie, quentin]
let ageIs33Predicate01 = NSPredicate(format: "age = 33")
let ageIs33Predicate02 = NSPredicate(format: "%K = 33", "age")
let ageIs33Predicate03 = NSPredicate(format: "%K = %#", "age","33")
let ageIs33Predicate04 = NSPredicate(format: "age = %#","33")
(people as NSArray).filtered(using: ageIs33Predicate01)
// ["Charlie Smith"]
(people as NSArray).filtered(using: ageIs33Predicate02)
// ["Charlie Smith"]
(people as NSArray).filtered(using: ageIs33Predicate03)
// []
(people as NSArray).filtered(using: ageIs33Predicate04)
// []
What am I doing wrong? Thanks.
Why would the last two work? You are passing a String in for an Int property. You need to pass in an Int to compare against the Int property.
Change the last two to:
let ageIs33Predicate03 = NSPredicate(format: "%K = %d", "age", 33)
let ageIs33Predicate04 = NSPredicate(format: "age = %d", 33)
Note the change in the format specifier from %# to %d.
Related
Four errors:
I don't understand why these complier errors are occurring. Did I not initialize "name", "empNum", "birthdate" and "department"?
#MainActor class EmployeeViewModel: ObservableObject {
#Published var name = ""
#Published var empNum = ""
#Published var birthdate = Date(timeIntervalSince1970: 0)
#Published var dept = ""
init(name: String = "", empNum: String = "", birthdate: Date = Date(timeIntervalSince1970: 0), dept: String = "") {
self.name = name
self.empNum = empNum
self.birthdate = birthdate
self.dept = dept
}
#Published var userData: [Employee] = [
Employee(name: name, empNum: empNum, birthdate: birthdate, department: dept) //ERRORs Here
]
}
Here is my data model:
struct Employee: Codable, Identifiable {
var id = UUID()
var birthdate = Date(timeIntervalSince1970: 0)
var name = ""
var empNum = "8675309"
var department = ""
init(id: UUID = UUID(), birthdate: Date = Date(timeIntervalSince1970: 0), name: String = "", empNum: String = "8675309", department: String = "") {
self.id = id
self.birthdate = birthdate
self.name = name
self.empNum = empNum
self.department = department
}
}
I having this problem when I inserting data row and the result comes out 'SUCCESS'. But when I print out the table, something like below came out. I have been trying on this for days but couldn't figure out where whet wrong.
Logs:
Successfully inserted row. >> aaa sss ddd fff
Successfully inserted row. >> zzz xxx ccc vvv
Successfully inserted row. >> 9999999 00000000 aaaaaaa bbbbbbbbbbbbb
Successfully inserted row. >> ccccccccccccc ddddddddddd eeeeeeeeeeee fffffffffffffffff
Successfully inserted row. >> gggggggggggg hhhhhhhhhhhh iiiiiiiiiiiii jjjjjjjjjjjjjj
Successfully inserted row. >> kkkkkkkkkkk LLLLLLLLLL mmmmmmmm nnnnnnnnnnnnn
Query Result= id:1 msgID:fff loginID:fff conversationID:fff userID:fff
Query Result= id:2 msgID:vvv loginID:vvv conversationID:vvv userID:vvv
Query Result= id:3 msgID:bbbbbbb loginID:bbbbbbb conversationID:bbbbbbbb userID:bbbbbbbbbbbbb
Query Result= id:4 msgID:ddddddddddd loginID:ddddddddddd conversationID:ddddddddddd userID:fffffffffffffffff
Query Result= id:5 msgID:jjjjjjjjjjjjj loginID:jjjjjjjjjjjj conversationID:jjjjjjjjjjjj userID:jjjjjjjjjjjjjj
Query Result= id:6 msgID:nnnnnnnn loginID:nnnnnnnnnnn conversationID:nnnnnnnnnn userID:nnnnnnnnnnnnn
I'm sure the database connection is fine, but it just came out wrong. I even checked if my parameters are input correctly.
When I call my function:
DB_Handler.add_msgstatus(loginID: "aaa", conversationID: "sss", msgID: "ddd", userID: "fff")
DB_Handler.add_msgstatus(loginID: "zzz", conversationID: "xxx", msgID: "ccc", userID: "vvv")
DB_Handler.add_msgstatus(loginID: "9999999", conversationID: "00000000", msgID: "aaaaaaa", userID: "bbbbbbbbbbbbb")
DB_Handler.add_msgstatus(loginID: "ccccccccccccc", conversationID: "ddddddddddd", msgID: "eeeeeeeeeeee", userID: "fffffffffffffffff")
DB_Handler.add_msgstatus(loginID: "gggggggggggg", conversationID: "hhhhhhhhhhhh", msgID: "iiiiiiiiiiiii", userID: "jjjjjjjjjjjjjj")
DB_Handler.add_msgstatus(loginID: "kkkkkkkkkkk", conversationID: "LLLLLLLLLL", msgID: "mmmmmmmm", userID: "nnnnnnnnnnnnn")
DB_Handler.getAllMsgStatusInfo()
My insert row function:
static func add_msgstatus(loginID: String, conversationID: String, msgID: String, userID: String) {
let queryString = "INSERT INTO msgstatus_tbl (id, msg_id, login_id, conversation_id, user_id) VALUES (null, ?, ?, ?, ?);"
var preparedStmt: OpaquePointer? = nil
if sqlite3_prepare(db, queryString, -1, &preparedStmt, nil) == SQLITE_OK {
sqlite3_bind_text(preparedStmt, 1, msgID, -1, nil)
sqlite3_bind_text(preparedStmt, 2, loginID, -1, nil)
sqlite3_bind_text(preparedStmt, 3, conversationID, -1, nil)
sqlite3_bind_text(preparedStmt, 4, userID, -1, nil)
if sqlite3_step(preparedStmt) == SQLITE_DONE {
print("Successfully inserted row. >> \(loginID) \(conversationID) \(msgID) \(userID)")
} else {
let errorMessage = String.init(cString: sqlite3_errmsg(db))
print("Fail to insert row. \(errorMessage)")
}
sqlite3_finalize(preparedStmt)
} else {
let errorMessage = String.init(cString: sqlite3_errmsg(db))
print("Unable to prepare statement. \(errorMessage)")
}
}
My table:
static func create_msgstatus_tbl() {
let queryString = "CREATE TABLE IF NOT EXISTS msgstatus_tbl (id INTEGER PRIMARY KEY, msg_id VARCHAR(255), login_id VARCHAR(255), conversation_id VARCHAR(255), user_id VARCHAR(255));"
var preparedStmt: OpaquePointer? = nil
if sqlite3_prepare_v2(db, queryString, -1, &preparedStmt, nil) == SQLITE_OK {
if sqlite3_step(preparedStmt) == SQLITE_DONE {
print("Table (msgstatus_tbl) exists/ created.")
} else {
print("Table (msgstatus_tbl) could not be created.")
}
sqlite3_finalize(preparedStmt)
} else {
let errorMessage = String.init(cString: sqlite3_errmsg(db))
print("Unable to prepare statement. \(errorMessage)")
}
}
My retrieve data function:
static func getAllMsgStatusInfo() {
let queryString = "SELECT * FROM msgstatus_tbl;"
var preparedStmt: OpaquePointer? = nil
if sqlite3_prepare_v2(db, queryString, -1, &preparedStmt, nil) == SQLITE_OK {
var msgID = ""
var loginID = ""
var conversationID = ""
var userID = ""
var id = ""
while (sqlite3_step(preparedStmt) == SQLITE_ROW) {
id = String(cString: sqlite3_column_text(preparedStmt, 0))
msgID = String(cString: sqlite3_column_text(preparedStmt, 1))
loginID = String(cString: sqlite3_column_text(preparedStmt, 2))
conversationID = String(cString: sqlite3_column_text(preparedStmt, 3))
userID = String(cString: sqlite3_column_text(preparedStmt, 4))
print("Query Result= id:\(id) msgID:\(msgID) loginID:\(loginID) conversationID:\(conversationID) userID:\(userID)")
}
sqlite3_finalize(preparedStmt)
} else {
let errorMessage = String.init(cString: sqlite3_errmsg(db))
print("Unable to prepare statement. \(errorMessage)")
}
}
You need to do one thing.
When you use sqlite3_bind_text(preparedStmt, 1, msgID, -1, nil) then just follow these following steps -:
let msgId = msgID as NSString
sqlite3_bind_text(preparedStmt, 1, msgId.utf8String, -1, nil)
Do these same things for all your next sqlite3_bind_text statement as mentioned in your code.
I also faced same problem like you. And it is working now for me. I hope it will work for you.
I want to receive some text that has been inputted by the user on an Apple Watch. This is what I have so far:
presentTextInputController(withSuggestions: ["Michael","David","John","Lisa","Mary","Susan","Matthew","James","Jessica","Jennifer","Amanda","Emily","Dylan","Ross","Rupert"], allowedInputMode: WKTextInputMode.plain) { (arr: [Any]?) in
playerNames.playerOne = String(describing: arr)
print(playerNames.playerOne)
}
This always returns a optional like Optional([Michael])
I want it to return Michael
I have looked around about optionals but can't seem to find an anwser.
You can try this code:
let suggestions = ["Michael", "David", "John", "Lisa", "Mary", "Susan", "Matthew", "James", "Jessica", "Jennifer", "Amanda", "Emily", "Dylan", "Ross", "Rupert"]
presentTextInputController(withSuggestions: suggestions, allowedInputMode: WKTextInputMode.plain) { (arr: [Any]?) in
guard let arr = arr, let firstElement = arr.first as? String else { return }
playerNames.playerOne = firstElement
print(playerNames.playerOne)
}
Here are some documents you can refer to: Optional Binding, Guard Statement.
I am writing a basic iOS app to test my Swift knowledge and keep on practicing. In my app the user types a name for a baby, then turns a switch either on or off to set the gender/sex and also change the system color.
After that, the name is used to fill in a UITextView, named "firstWords", in the following block of code:
// Save name entered into text field
#IBAction func saveSettings(_ sender: UIButton) {
nameLabel.text = nameTextField.text
if nameTextField.text == "" {
showMessage()
nameLabel.text = "Baby Name"
}
nameTextField.resignFirstResponder()
let nameHolder: String! = nameLabel.text
if boyGirlSwitch.isOn {
let sex = ("boy", "his", "he", "Boy", "His", "He")
} else {
let sex = ("girl", "her", "she", "Girl", "Her", "She")
}
firstWords.text = "Wow, " + nameHolder + " has so much to look forward to!" + (sex.5) + " will do so many great things!"
}
I keep getting an error at the tuple (sex.5) inside firstWords that says: "Use of unresolved identifier 'sex'"
As I understand it, the constant sex is declared within the if statement and the compiler does go through it either way, so it does get identified and declared.
QUESTION: Why am I getting the error?
Thanks in advance! Here's a screenshot of my code as well:
Screenshot of block of code as described above, including the compiler/build-error
This is a scope issue. sex is only available within the else clause.
You can fix it like this
// Save name entered into text field
#IBAction func saveSettings(_ sender: UIButton) {
nameLabel.text = nameTextField.text
if nameTextField.text == "" {
showMessage()
nameLabel.text = "Baby Name"
}
nameTextField.resignFirstResponder()
let nameHolder: String! = nameLabel.text
var sex : (String, String, String, String, String, String)
if boyGirlSwitch.isOn {
sex = ("boy", "his", "he", "Boy", "His", "He")
} else {
sex = ("girl", "her", "she", "Girl", "Her", "She")
}
firstWords.text = "Wow, " + nameHolder + " has so much to look forward to!" + (sex.5) + " will do so many great things!"
}
this way sex is defined within the scope of the whole IBAction and will be available in the end.
you could also skip one condition if you pre-declare it with a default:
// Save name entered into text field
#IBAction func saveSettings(_ sender: UIButton) {
nameLabel.text = nameTextField.text
if nameTextField.text == "" {
showMessage()
nameLabel.text = "Baby Name"
}
nameTextField.resignFirstResponder()
let nameHolder: String! = nameLabel.text
var sex = ("girl", "her", "she", "Girl", "Her", "She")
if boyGirlSwitch.isOn {
sex = ("boy", "his", "he", "Boy", "His", "He")
}
firstWords.text = "Wow, " + nameHolder + " has so much to look forward to!" + (sex.5) + " will do so many great things!"
}
There is actually a nice article about variable scope on Wikipedia: https://en.wikipedia.org/wiki/Scope_(computer_science)
I have this class with some optional properties:
class Address {
var Id: Int64
var AddressType: Int64
var AddressStatus: Int64
var Address1: String?
var Address2: String?
var City: String?
var State: String?
var Zip: String?
var Country: String?
var Latitude: Double?
var Longitude: Double?
}
I am trying to insert into a Sqlite database, like this:
let insert = table.insert(or: .replace, Id <- item.Id, AddressType <- item.AddressType, AddressStatus <- item.AddressStatus, Address1 <- item.Address1?, Address2 <- item.Address2?, City <- item.City?, State <- item.State?, Zip <- item.Zip?, Country <- item.Country?, Latitude <- item.Latitude?, Longitude <- item.Longitude?)
But I get this build error:
Value of optional type 'String?' not unwrapped; did you mean to use '!' or '?'?
If I use '!' it will build, but I get this error when I run:
unexpectedly found nil while unwrapping an Optional value
I am still new to Swift, but from what I know, I don't want to use '!' when the value can be nil, correct?
I'm not sure what I'm doing wrong here.
Make all your class properties constants (declare with let) and make them non optional adding a required init() with all your Address properties parameters. BTW it is Swift convention to start your vars naming with a lowercase letter. Note: You should use Int instead of Int64 unless it is a requirement. Regarding the optionality of your properties you can just assign a default value for them at initialization time. Btw It is better to use a struct unless you need to make your object persist (NSCoding compliant):
struct Address {
let id: Int
let addressType: Int
let addressStatus: Int
let address1: String
let address2: String
let city: String
let state: String
let zip: String
let country: String
let latitude: Double?
let longitude: Double?
init(id: Int, addressType: Int, addressStatus: Int, address1: String = "", address2: String = "", city: String = "", state: String = "", zip: String = "", country: String = "", latitude: Double = nil, longitude: Double = nil) {
self.id = id
self.addressType = addressStatus
self.addressStatus = addressStatus
self.address1 = address1
self.address2 = address2
self.city = city
self.state = state
self.zip = zip
self.country = country
self.latitude = latitude
self.longitude = longitude
}
}
So you can create your new object Address as follow:
let address1 = Address(id: 1, addressType: 2, addressStatus: 3)
let address2 = Address(id: 2, addressType: 3, addressStatus: 4, address1: "Any Address", latitude: 22.0, longitude: 43.0) // You don't need to add all parameters as long as you keep them in the same order as your initializer
address2.latitude // 22.0