Swift 4.2 computed variable [String:Bool] does not assign value correctly - swift

[MacOS 10.14.1, Xcode 10.1, Swift 4.2]
I'm working on creating a getopt style CLI argument processor whilst practising Swift. In my design, I decided to create a computed variable, represented as a [String:Bool] dictionary, that can be checked to see if an option (key) is just a switch (value = true) or whether it may include parameters (value = false). So I've written the code below, all of which is, at the moment, in my small (300 lines) main.swift file.
The code works correctly in a playground, but in my Swift Xcode project, whilst the dictionary's keys are correct, values are always false and inconsistent with the printed messages.
let options = "cwt:i:o:"
//lazy var optionIsSwitch : [String:Bool] = { (This will be moved to a class)
var optionIsSwitch : [String:Bool] = {
var tmpOptionIsSwitch : [String:Bool] = [:]
let optionsStrAsArray = Array(options)
let flags = Array(options.filter { !":".contains($0) } )
tmpOptionIsSwitch.reserveCapacity(flags.count)
for thisOption in 0...flags.count-1 {
var posInOptionsStr = 0
while posInOptionsStr < optionsStrAsArray.count-1 && flags[thisOption] != optionsStrAsArray[posInOptionsStr] {
posInOptionsStr += 1
}
if posInOptionsStr < optionsStrAsArray.count-1 && optionsStrAsArray[posInOptionsStr+1] == ":" {
tmpOptionIsSwitch[String(flags[thisOption])] = false
print("\(flags[thisOption]) is FALSE")
} else {
tmpOptionIsSwitch[String(flags[thisOption])] = true
print("\(flags[thisOption]) is TRUE")
}
}
return tmpOptionIsSwitch
}()
I've stepped through the code in my project to observe the execution sequence, and found it to be correct. As per the first image, tmpOptionIsSwitch returns a dictionary containing the right keys but all the values are set to false, which is inconsistent with the print statements.
As part of my debugging activities, I copied the above code into a Swift Playground where I found it gave the correct results, as per the image below.
Has anyone has such an issue? Is there something I've done wrong?

Related

first or filter function of swift array doesnt give the right reference object

I have defined a struct in my viewcontroller before my viewdidload
struct CustomFilterButton {
var Id : Int = 0;
var Name : String = "";
var selected : Bool = false;
}
then I create reference for it in global
var customButtons = [CustomFilterButton]();
then in my viewdidload I appended some customFilterButton objects in customButtons array
customButtons.append(CustomFilterButton.init(Id: 1, Name: "A", selected: false))
customButtons.append(CustomFilterButton.init(Id: 2, Name: "B", selected: false))
customButtons.append(CustomFilterButton.init(Id: 3, Name: "C", selected: true))
customButtons.append(CustomFilterButton.init(Id: 4, Name: "D", selected: false))
in viewdidload or in any other function when I try to get an object in array using first or filter and change it, but it doesnt work.
print(customButtons[0].selected);
print("--")
var bt = customButtons.first{
$0.Id == 1
}
bt?.selected = true;
print(bt?.selected);
print(customButtons[0].selected);
here is the result
false
--
Optional(true)
false
the same applies to filter also!
Am I missing something or am I doing something wrong?
Note: I need to get the object that first or filter found and change it, not the hard copy of it
When you deal with a Struct, you have to understand that it is a value type.
So, that means that everytime you pass a value around, it's a COPY of the value and not the reference
And when you do this:
var bt = customButtons.first{
$0.Id == 1
}
You're asking the compiler to retrieve a copy of the CustomFilterButton whose Id is 1 and assign the copy to your bt variable.
To tackle this, you can access the element by its index and directly modify its value without passing it around (assigning to a new variable)
// Get the index of the element you're trying to modify
if let indexYouWantToModify = customButtons.firstIndex(where: {$0.Id == 1}){
// Modify it directly through its index
customButtons[indexYouWantToModify].selected = true
}
Oh, and though changing your Struct to a Class works for you, I think it's unnecessary just for this little use case. Structs and Classes hold their own benefits and trade-offs. I'm not sure what you're planning to do over this CustomFilterButton over the long run so I suggest you to read this article and decide for yourselves!
var bt = customButtons.first{
$0.Id == 1
}
At this moment bt has no any relation to your customButtons[0], its value was copied.
Access to item by index
print(customButtons[0].selected);
print("--")
var offset = 0
var bt = customButtons.enumerated().first{
if $0.element.Id == 1 {
offset = $0.offset
return true
}
return false
}
customButtons[offset].selected = true;
print(customButtons[0].selected);
You should use class instead of struct.

Why is my lineString not converting to mapShape in geoSwift - (only happens with one specific search), could be external library bug?

Im using the GEOSwift Library: https://github.com/GEOSwift/GEOSwift
My best guess is that if you look at the string image linked, it looks as if its not a proper circle, so maybe it is a bug in the library? But i am not at all sure about this!
Im having an issue only when i enter one specific linestring.
My app takes an array of route coordinates, converts them into WKT String (representing a line). It then Creates a buffer around this line, then converts this into a mapShape.
It runs fine, until i search one specific route.
It fails here:
func bufferPolyline(routeCoords: [CLLocationCoordinate2D], completion: #escaping (_ bufferCoordsArray: [LatLng]) -> ()) {
var wktString = ""
var i = 0
while i < routeCoords.count {
let lat = routeCoords[i].latitude
let lng = routeCoords[i].longitude
if i == routeCoords.count-1 {
let wktLast = " \(lng) \(lat)"
wktString += "\(wktLast)"
i += 1
}
if i >= 1 && i <= routeCoords.count-2 {
let wktMid = " \(lng) \(lat),"
wktString += "\(wktMid)"
i += 1
}
if i == 0 {
let wktFirst = "\(lng) \(lat),"
wktString += "\(wktFirst)"
i += 1
}
}
let linestring = Geometry.create("LINESTRING(\(wktString))")!
let string = linestring.buffer(width: 0.05)!
guard let shapeLine = string.mapShape() as? MKPolygon else {
preconditionFailure() // FAILURE HAPPENS HERE.
}
}
Here are links to images to see how it looks:
LineString - https://imgur.com/a/7OLPZkM
String - https://imgur.com/a/KJRfpRX
the linestring, and string values are still coming through even when shapeLine doesnt initialise so im struggling to see where im going wrong. They also seem to be formatted the same way.
I tried to google for a WKT String validator, but didnt find one, but i assume it should be ok, as i return multiple other searches with no issues. (i.e. the shapeLine returns a value)
My question is: does this look like a problem in my code, or a possible bug of the library? (i have little faith in my code!)

Set Single Elements in Dictionary of Dictionaries

I have a question regarding a Dictionary of Dictionaries. Is there a shorter way to put single elements in the Dict than I did?
var cellHeight = [ Int : [ Int : CGFloat ] ]()
// ...
if let _ = cellHeight[0] {
cellHeight[0]![2] = 0.0
} else {
cellHeight[0] = [ 2 : 0.0 ]
}
In all the tutorials I checked it's only explained how to fill/initialize the full dict-of-dict and than read from it, but not how to fill it part by part.
Simply add the element. If an entry into a dictionary does not exist yet, adding an element to that key will create one. If a key already exists, then adding an element will overwrite the old one. Reading from a dictionary key that does not exist will return nil. Reading from a dictionary returns an optional.
What you're doing is basically right. You can be slightly more elegant, like this:
let didit = cellHeight[0]?[2] = 0 // yields an Optional<Void>
if didit == nil { // that didn't work, so create the entry
cellHeight[0] = [2:0]
}
And that can be tightened up even further, without the extra variable:
if nil == (cellHeight[0]?[2] = 0) {
cellHeight[0] = [2:0]
}
If this is a recurring pattern in your code, you can of course abstract it into a function.

Why in swift are variables option in a function but not in playground

I am puzzled. I need to compare product date codes. they look like 12-34-56. I wrote some code to break the parts up and compare them. this code works fin in the play ground. But when i make it a function in a view controller values come up NIL and i get a lot of "Optional("12-34-56")" values when printed to the log or viewed in a break. I tried unwrapping in many locations but nothing takes.? don't be confused by the variables date and month because they are not product codes can have 90 days and 90 months depending on the production machine used.
func compaireSerial(oldNumIn: NSString, newNumIn: String) -> Bool {
// take the parts of the number and compare the pics on at a time.
// Set up the old Num in chunks
let oldNum = NSString(string: oldNumIn)
let oldMonth = Int(oldNum.substringToIndex(2))
let oldDay = Int(oldNum.substringWithRange(NSRange(location: 3, length: 2)))
let oldYear = Int(oldNum.substringFromIndex(6))
print(oldMonth,oldDay, oldYear)
// Set up the new Num in chunks
let newNum = NSString(string: newNumIn)
let newMonth = Int(newNum.substringToIndex(2))
let newDay = Int(newNum.substringWithRange(NSRange(location: 3, length: 2)))
let newYear = Int(newNum.substringFromIndex(6))
print(newMonth, newDay, newYear)
// LETS Do the IF comparison steps.
if oldYear < newYear {
return true
} else if oldMonth < newMonth {
return true
} else if oldDay < newDay {
return true
} else {
return false
}
}
May thanks to any one. Im totally stumped
All Int() initializers with String parameters return always an optional Int.
The realtime result column in a Playground doesn't indicate the optional but printing it does.
let twentyTwo = Int("22") | 22
print(twentyTwo) | "Optional(22)\n"
I don't see how i can delete my question so ill post this to let others know it is fixed. Turns out the auction works okay but the NSUserDefaults value coming in was optional. So i was feeding the optional in. After unwrapping the NSUser value all works.

Unwrap String and check emptiness in the same if statement

I want to achieve this
if let large = imageLinks.large {
if !large.isEmpty {
result = large
}
}
in a single if statement, something like this (this does not compiles)
if let large = imageLinks.large where !large.isEmpty {
result = large
}
Is it possible?
It 's not yet possible.
With the actual Version of swift the if let statement is pretty poor.
But with Swift 1.2 (it will be available in Xcode 6.3).
You will be able to do this:
(SWIFT 1.2)
if let large = imageLinks.large where !large.isEmpty {
result = large
}
But now you cannot.
You can do something like:
if imageLinks.large != nil && !imageLinks.large!.isEmpty {
result = large!;
}
Note:
Swift use "Lazy Evaluation"
If the first part imageLinks.large != nil is false it will not Evaluate the second part, so it will not crash.
But I don't found this solution beautiful (too much force unwrapping).
In swift 4.4, generics to the rescue \o/
public extension Optional where Wrapped == String {
var isEmptyOrNil: Bool { (self ?? "").isEmpty }
}
usage
if nameField.text.isEmptyOrNil {
//doSomething...
}
In Swift 1.1
If you don't like force unwrapping, you can:
if let large = imageLinks.large?.isEmpty == false ? imageLinks.large : nil {
result = large
}
It's not so beautiful anyway :(