How to insert into Sqlite with optional parameters using Swift 3 - swift3

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

Related

SwiftUI: Cannot use instance member 'x' within property initializer; property initializers run before 'self' is available

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
}
}

Pick conditional values from ForEach in SwiftUI

I have this struct created.
struct MedItem: Identifiable {
let id = UUID() //Generates a unique string for each item listed below
let medThumbnail: String
let medTitle: String
let medDose: String
let medDoseval: String
let purpose: String
let takeAt: String
let refillDate: String
let refillRem: String
}
With this data added:
struct MedData {
static let mListData = [
MedItem(medThumbnail: "Levo", medTitle: "Levothyroxine", medDose: "15", takeAt: "8 am", medDoseval: "mcg", purpose: "Hypothyroidism", refillDate: "December 3, 2021", refillRem: "Refill Remaning: 1"),
] //Imagine more sample data here
I'm trying to sort values based on time range linked to the timeAt value.
ForEach (meds, id: \.id) { MedItem in
HStack(spacing: 10.0){
}
If time is between 2am - 12pm then morning, 12pm - 3pm then noon, 3pm - 6pm evening, and 7pm - 2am then night. Some meds will not have a time and they need to be catoegorized in a different bucket.
Thank you for your help :)

SWIFT 3 Predicate for NSArray not working properly with numbers

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.

Swift: Splitting Strings by RegEx [duplicate]

I am attempting to use regular expression to replace all occurrences of UK car registrations within a string.
The following swift code works perfectly for a when the string matches the regex exactly as below.
var myString = "DD11 AAA"
var stringlength = countElements(myString)
var ierror: NSError?
var regex:NSRegularExpression = NSRegularExpression(pattern: "^([A-HK-PRSVWY][A-HJ-PR-Y])\\s?([0][2-9]|[1-9][0-9])\\s?[A-HJ-PR-Z]{3}$", options: NSRegularExpressionOptions.CaseInsensitive, error: &ierror)!
var modString = regex.stringByReplacingMatchesInString(myString, options: nil, range: NSMakeRange(0, stringlength), withTemplate: "XX")
print(modString)
The result is XX
However, the following does not work and the string is not modifed
var myString = "my car reg 1 - DD11 AAA my car reg 2 - AA22 BBB"
var stringlength = countElements(myString)
var ierror: NSError?
var regex:NSRegularExpression = NSRegularExpression(pattern: "^([A-HK-PRSVWY][A-HJ-PR-Y])\\s?([0][2-9]|[1-9][0-9])\\s?[A-HJ-PR-Z]{3}$", options: NSRegularExpressionOptions.CaseInsensitive, error: &ierror)!
var modString = regex.stringByReplacingMatchesInString(myString, options: nil, range: NSMakeRange(0, stringlength), withTemplate: "XX")
print(modString)
The result is my car reg 1 - DD11 AAA my car reg 2 - AA22 BBB
Can anyone give me any pointers?
You need to remove the ^ and $ anchors.
The ^ means start of string and $ means end of string (or line, depending on the options). That's why your first example works: in the first test string, the start of the string is really followed by your pattern and ends with it.
In the second test string, the pattern is found in the middle of the string, thus the ^... can't apply. If you would just remove the ^, the $ would apply on the second occurrence of the registration number and the output would be my car reg 1 - DD11 AAA my car reg 2 - XX.
let myString = "my car reg 1 - DD11 AAA my car reg 2 - AA22 BBB"
let regex = try! NSRegularExpression(pattern: "([A-HK-PRSVWY][A-HJ-PR-Y])\\s?([0][2-9]|[1-9][0-9])\\s?[A-HJ-PR-Z]{3}", options: NSRegularExpression.Options.caseInsensitive)
let range = NSMakeRange(0, myString.count)
let modString = regex.stringByReplacingMatches(in: myString, options: [], range: range, withTemplate: "XX")
print(modString)
// Output: "my car reg 1 - XX my car reg 2 - XX"
Let's use a class extension to wrap this up in Swift 3 syntax:
extension String {
mutating func removingRegexMatches(pattern: String, replaceWith: String = "") {
do {
let regex = try NSRegularExpression(pattern: pattern, options: .caseInsensitive)
let range = NSRange(location: 0, length: count)
self = regex.stringByReplacingMatches(in: self, options: [], range: range, withTemplate: replaceWith)
} catch { return }
}
}
var phoneNumber = "+1 07777777777"
phoneNumber.removingRegexMatches(pattern: "\\+\\d{1,4} (0)?")
Results in 7777777777 (thus removing country code from phone number)
Swift 4.2 Updated
let myString = "my car reg 1 - DD11 AAA my car reg 2 - AA22 BBB"
if let regex = try? NSRegularExpression(pattern: "([A-HK-PRSVWY][A-HJ-PR-Y])\\s?([0][2-9]|[1-9][0-9])\\s?[A-HJ-PR-Z]{3}", options: .caseInsensitive) {
let modString = regex.stringByReplacingMatches(in: myString, options: [], range: NSRange(location: 0, length: myString.count), withTemplate: "XX")
print(modString)
}
Update for Swift 2.1:
var myString = "my car reg 1 - DD11 AAA my car reg 2 - AA22 BBB"
if let regex = try? NSRegularExpression(pattern: "([A-HK-PRSVWY][A-HJ-PR-Y])\\s?([0][2-9]|[1-9][0-9])\\s?[A-HJ-PR-Z]{3}", options: .CaseInsensitive) {
let modString = regex.stringByReplacingMatchesInString(myString, options: .WithTransparentBounds, range: NSMakeRange(0, myString.characters.count), withTemplate: "XX")
print(modString)
}
Warning
Do not use NSRange(location: 0, length: myString.count) as all examples above quoted.
Use NSRange(myString.startIndex..., in: myString) instead!
.count will count newline characters like \r\n as one character - this may result in a shortened, thus invalid, NSRange that does not match the whole string.
(.length should work)
With pattern: "^ ... $" you have specified that the pattern is anchored
to the start and end of the string, in other words, the entire string
must match the pattern. Just remove ^ and $ from the pattern
and you'll get the expected result.
Simple extension:
extension String {
func replacingRegex(
matching pattern: String,
findingOptions: NSRegularExpression.Options = .caseInsensitive,
replacingOptions: NSRegularExpression.MatchingOptions = [],
with template: String
) throws -> String {
let regex = try NSRegularExpression(pattern: pattern, options: findingOptions)
let range = NSRange(startIndex..., in: self)
return regex.stringByReplacingMatches(in: self, options: replacingOptions, range: range, withTemplate: template)
}
}
✅ Advantages to other answers
Exposed throwing error to the caller
Exposed finding options to the caller with default for the ease of use
Exposed replacing options to the caller with default for the ease of use
Fixed the range BUG 🐞 in the original answer
A notice to all answers that uses .count in their answers:
This will cause problems in cases that the operating target range has surrogate-paired characters.
Please fix your answers by using .utf16.count instead.
Here's Ryan Brodie 's answer with this fix. It works with Swift 5.5.
private extension String {
mutating func regReplace(pattern: String, replaceWith: String = "") {
do {
let regex = try NSRegularExpression(pattern: pattern, options: [.caseInsensitive, .anchorsMatchLines])
let range = NSRange(location: 0, length: self.utf16.count)
self = regex.stringByReplacingMatches(in: self, options: [], range: range, withTemplate: replaceWith)
} catch { return }
}
}
Update: If considering #coyer 's concerns:
private extension String {
mutating func regReplace(pattern: String, replaceWith: String = "") {
do {
let regex = try NSRegularExpression(pattern: pattern, options: [.caseInsensitive, .anchorsMatchLines])
let range = NSRange(self.startIndex..., in: self)
self = regex.stringByReplacingMatches(in: self, options: [], range: range, withTemplate: replaceWith)
} catch { return }
}
}
Also: to #Martin R' :
It is okay to use ^ and $ in Regex as long as you have enabled the ".anchorsMatchLines" in the Regex options. I already applied this option in the codeblocks above.

How to find which group is matched in NSRegularExpression

I have a regex statement with multiple capture groups which are separated by | operator. How can I find out which capture group is matched? Only way I can think of -for this example- is counting the number of characters if something is matched.
var string = "1234567897"
var pattern = "(^\\d{9}$)|(^\\d{10}$)|(^\\d{13}$)|(^[a-zA-Z]{2}\\d{9}[a-zA-Z]{2}$)"
var myRegex = NSRegularExpression(pattern: pattern, options: nil, error: nil)!
if let myMatch = myRegex.firstMatchInString(string, options: nil,
range: NSRange(location: 0, length: string.utf16Count)) {
println((string as NSString).substringWithRange(myMatch.rangeAtIndex(0)))
}
I wrote a code which worked for my example. I am sure it can be written better way but it works for now.
Swift 2.3
var string = "123456789"
var pattern = "(^\\d{9}$)|(^\\d{10}$)|(^\\d{13}$)|(^[a-zA-Z]{2}\\d{9}[wW]{2}$)"
var myRegex = try! NSRegularExpression(pattern: pattern, options: [])
if let myMatch = myRegex.firstMatchInString(string, options: NSMatchingOptions.init(rawValue: 0), range: NSRange(location: 0, length: string.utf16.count)) {
var matchedGroup = 0
for var i in 1..<myMatch.numberOfRanges {
if myMatch.rangeAtIndex(i).length != 0 {
matchedGroup = i
break
}
}
print(matchedGroup)
print((string as NSString).substringWithRange(myMatch.rangeAtIndex(0))) //whatever the range you want to print
}
Swift 3
var string = "123456789"
var pattern = "(^\\d{9}$)|(^\\d{10}$)|(^\\d{13}$)|(^[a-zA-Z]{2}\\d{9}[wW]{2}$)"
var myRegex = try! NSRegularExpression(pattern: pattern, options: [])
if let myMatch = myRegex.firstMatch(in: string, options: NSRegularExpression.MatchingOptions.init(rawValue: 0), range: NSRange(location: 0, length: string.utf16.count)) {
var matchedGroup = 0
for var i in 1..<myMatch.numberOfRanges {
if myMatch.rangeAt(i).length != 0 {
matchedGroup = i
break
}
}
print(matchedGroup)
print((string as NSString).substring(with: myMatch.rangeAt(0))) //whatever the range you want to print
}