Hi Claude, thanks a lot for the reply!!!
I already had tried that way you show, without the constructor, simply: var config = Config()
Same thing! So I moved to the implicit init construct. Well in my code I have a function that output to another struct (Instrumentation) such:
func getInstrumentation() -> Instrumentation {
var instrumentation: STInstrumentation
/* do some simple stuff here like declare other vars
... put the need values to function and one of that information is, eg., isVirtualMachine, but this data comes from the Config
.... so it will crash right here whatever use/call it do >>> */
if config.isVirtualMachine { do something } // will crash here if this is the 1st line
instrumentation.isVirtualMachine = config.isVirtualMachine // **this is the actual line in my code where it crashes:(**
}
That "if config" is just an example, the real code uses the line below, the only way I had to search for this error was doing that, as in my computer it won't raise any error and I cant make remote debug (I don't even know if Swift does that). I am telling that line crashes but any attempt to read any of the config properties will make it fail.
EDIT: I made a change and sent to the client to him a try (waiting for the answer), I change the function declaration to func getInstrumentation(configInformation: STConfig) -> STInstrumentation and now I am passing the config as parameter. Hope it can fix. Anyway fixed or not I really can't understand why with some devices it works.
Post
Replies
Boosts
Views
Activity
When I say other devices I mean about other Mac OS with same or different versions, Big Sur, Monterey, etc. Some it will give the error and a lot of are running ok. I will try simplify the code, using only these properties of the Config, as it is where we get the error whatever property I try to access (the actual struct have a lot of other properties):
struct STInstrumentation: Codable {
var logging: Bool = false
var isServer: Bool = false
var isVerbose: Bool = false
var isVirtualMachine: Bool = false
mutating func reset() {
self = STInstrumentation()
}
}
struct Config {
var logging = false
var isServer = false
var isVerbose = false
var isVirtualMachine = false
}
func getInstrumentation() -> STInstrumentation {
var instrumentation: Instrumentation
// while copying from the real code to here I notice that this local instrumentation isn't initialized...
instrumentation = STInstrumentation.init() // << this line is not present into my code, just put it now
// config var struct is global, but right now I am sending it as parameter
// STInstrumentation() receives more parameters, but only the config will raise the exception
// this error occurs even if before there like the example before
if config.isServer { print("wont print, it will crash") }
instrumentation = STInstrumentation(logging: config.logging, isServer: isServer: config.isServer,
isVerbose: config.isVerbose, isVirtualMachine: config.isVirtualMachine)
return instrumentation
}
var config = Config() // global config var
var Instrumentation: STInstrumentation // global Instrumentation var
Instrumentation = STInstrumentation.init()
// the information to the Config is from a SQLite, no issues here
config.logging = true
config.isServer = true
config.isVerbose = true
config.isVirtualMachine = false;
Instrumentation = getInstrumentation()
// ... from here the program continues with others stuff to do, including the use of the Instrumentation.
The terminal (this software is for terminal) will end with: zsh: trace trap /Applications/MyApplication
I still have to send to my client to him test with that init() but why it didn't crash before? By the way, the crash occurs only when trying to read the config value, this is why I modified to pass as parameter. The code you see here is such as what he has in hands now.
Thank you again and forgive me for my English too.
Print the config is all there, no issues!
> Config(logging: false, isServer: false, isVerbose: false, isVirtualMachine: false, isVip: false, endpoint: "gateway.xxxx.com", endpoint_scheme: "https", endpoint_path: "/api/receiver", endpoint_port: 5500, isApple: true)
I just sent another binary now instead of try: if config.isVirtualMachine { print("config.isVirtualMachine") } which crash here - this line is an attempt to the client help me to debug, i create a new global var configisVirtualMachine: Bool = false and I am setting its value and gonna try to use it instead of the config property value.. I am getting out of options here :(
Hi again
This is an app, compiled and running on the terminal. About the use of the function its just like test(param: str).
My real program is passing a struct property to the function, like test(param: myStruct.theString) the struct defines "theString" as String type. I really don't have a lot to show.
Actually I think I can add this, which is how the var passed to the function get its value:
myStruct.theString = (data.Value as! String).trimmingCharacters(in: .whitespacesAndNewlines)
The data.Value here is a string I read from a SQLite table. So when running
myStruct.theString = (data.Value as! String).trimmingCharacters(in: .whitespacesAndNewlines)
func(param: myStruct.theString)
Results output as:
Optional("Test")
This gives an error of invalid characters at my client computer,
but running the same code with my computer:
Test
There isn't mention to "Optional" and runs flawlessly
Here the real code, part of it:
// part of the struct
struct Config {
var endpoint: String
var endpoint_scheme: String
var endpoint_path: String
var endpoint_port: Int32
init() {
endpoint = ""
endpoint_path = ""
endpoint_port = 0
endpoint_scheme = ""
}
}
// part of the function that would sent data
func submitJson(jsonData: String, scheme: String, host: String, path: String, port: Int32, completion:((Error?) -> Void)?) -> Bool {
var urlComponents = URLComponents()
urlComponents.scheme = scheme
urlComponents.host = host
urlComponents.path = path
urlComponents.port = Int(port)
print(host) // this is just when I was trying to figure out what "invalid ' characters the app was complaining
guard let url = urlComponents.url else {
displayInfo(info: "URL configuration is invalid")
return false
}
// the rest of the code goes below, when it will fail to post the data due that invalid characters
}
// other place I should use:
var config = Config.init()
loadConfiguration() // somewhere it reads the SQLite
// and when need I will send some stuff based on the configuration
result = submitJson(jsonData: jsonDataStr, scheme: config.endpoint_scheme, host: config.endpoint, path: config.endpoint_path, port: config.endpoint_port)
Again, this works with my computer. That print won't display "Optional("anyendpoint.com")" but as an example in my computer it prints simple plain text "anyendpoint.com"
Thanks again
Hi man!
Well config is a global var, after this lines bellow I initiate var config = Config.init()
And Yes, loadConfiguration is populating the config, exatly like:
// after read the host field in the config table this is what I do:
config.endpoint = (data.Value as! String).trimmingCharacters(in: .whitespacesAndNewlines)
I also tried:
config.endpoint = String((data.Value as! String).trimmingCharacters(in: .whitespacesAndNewlines))
The data contains the value fetched from the table. Because of data.Value as! String I guess that the original string is an optional. How could I "fix" that? Or why would the program fail that way?
I figure out the issue but still unable to fix it.
Firstly, I made it stop working with me by replicating all the steps the user do.
Once the data is read from the SQLite table from a field type string (text typed in SQLite) using sql_column_text() function the result itself contains literal text of "Optional"and will break everything.
real code when I am attempting to fix, reading user department:
let stringValue = String(cString: sqlite3_column_text(Statement, index)) // attempt
This will show in the debugger as "Optional(\"Dev team\")" and the UI where the user changes the information, also shows exactly that way! All of this trouble after updating to XCode 5 (original was done with version 4). I opened the database using a 3rd party software and these characters are there!
Here how I read the data:
struct ColumnValue {
var Column: String
var Value: Any? // Need to be any because will support int, float, string at least.. using Any or Any makes no difference
}
var ResultSet: [ColumnValue]
var columnValue: ColumnValue
// ... after open database, now scroll the table
// simplified loop
while true {
for index in 0..<sqlite3_column_count(Statement) {
let column = String(cString: sqlite3_column_origin_name(Statement, index)!)
let type = sqlite3_column_type(Statement, index)
switch type {
// if column is type of string (text)
case SQLITE_TEXT, SQLITE3_TEXT:
let stringValue = String(cString: sqlite3_column_text(Statement, index)!)
columnValue = ColumnValue(Column: column, Value: stringValue)
default:
columnValue = ColumnValue(Column: column, Value: nilAny)
}
ResultSet.insert(columnValue, at: 0)
self.RowCount += 1
if sqlite3_step(Statement) == SQLITE_DONE { break }
}
}
All the issue is because stringValue is storing literal characters of the optional type. The information read should be a plain string like "Dev team", as I worked until now, and not that weird string "Optional(\"Dev team\")"
Hi Claude, sorry and thanks for you patience!!
I FIXED the issue!
Could you show how you get data ?
The data is typed in the user interface configuration form. I made a kind of helper to use the SQLite, so it can read and update tables and there was one of the issues.
With this helper I can handle the database and table as easy as:
var db: OpaquePointer?
var sqlQuery: sqliteQuery
var sqlText: OpaquePointer? = nil
let fileURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
.appendingPathComponent("/mydatabase.sqlite")
let sqlText = "INSERT INTO TABLE (user, password, status, date) VALUES (:user, :password, :status, :date);"
if sqliteOpenDatabase(DatabaseURL: fileURL, Database: &db) == SQLITE_OK {
sqlQuery = sqliteQuery(Database: &db, Statement: &sqlText, Query: queryString)
sqlQuery.ParamByName(Param: "user", ValueType: .string, Value: "Username" )
sqlQuery.ParamByName(Param: "password", ValueType: .string, Value: "123456" )
sqlQuery.ParamByName(Param: "status", ValueType: .string, Value: "valid" )
sqlQuery.ParamByName(Param: "date", ValueType: .date , Value: Date() )
sqlQuery.ExecSQL()
print(sqlQuery.ParamByName(Param: "user"))
}
Where do data come from ?
The data comes from a SQLite table
What is exactly in value ? Is it an optional ?
Think about saving a email field into a table. You should open the table and read something like "myname@site. com" (this forum dont allow type emails, so theres no space here, its an example) but once you read it (any program including and besides yourself) you would get as email a weird string as I was tolding: "Optional("myname@site. com")" and that messed up with everything.
To fix that I had to dig into the code and change all old Optional string convertions, even things like String(cString: value) are depreciated . Things such:
return anyData == nil ? "" : anyData as! String I had to change to return String(describing: anyData)
Also I had to perform a lot of changes in the ancient code. Again thanks for the support and patience!
Adding something else to this thread. Here a sample code that I use in my original code (not exactly this way, but the main part is quite close)
I started a new Command Line Tool with Xcode 14.2, i notice that there's no more config.plist so I take from my app to ensure that NSLocationAlwaysUsageDescription, NSLocationUsageDescription and NSLocationWhenInUseUsageDescription are there - config.plist attached here too. No luck with Ventura so far.
config.plist.txt
import Foundation
import CoreLocation
struct TCoordinates {
var latitude: Double = 0
var longitude: Double = 0
var altitude: Double = 0
var course: Double = 0
var precision: Double = 0
}
let locationManager = CLLocationManager()
var coordinates: TCoordinates
coordinates = TCoordinates.init()
func getCoordinates(locationManager: CLLocationManager) -> TCoordinates {
var ret = TCoordinates.init()
ret.latitude = locationManager.location?.coordinate.latitude ?? 0
ret.longitude = locationManager.location?.coordinate.longitude ?? 0
ret.altitude = locationManager.location?.altitude ?? 0
ret.course = locationManager.location?.course ?? 0
ret.precision = locationManager.location?.horizontalAccuracy ?? 0
return ret
}
private func locationManager(manager: CLLocationManager!, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
switch status {
case .notDetermined:
// If status has not yet been determied, ask for authorization
manager.requestWhenInUseAuthorization()
break
case .authorizedWhenInUse:
// If authorized when in use
manager.startUpdatingLocation()
break
case .authorizedAlways:
// If always authorized
manager.startUpdatingLocation()
break
case .restricted:
// If restricted by e.g. parental controls. User can't enable Location Services
break
case .denied:
// If user denied your app access to Location Services, but can grant access from Settings.app
break
default:
break
}
}
func getGeoLocation() {
coordinates = getCoordinates(locationManager: locationManager)
if CLLocationManager.locationServicesEnabled() {
let authorizationStatus: CLAuthorizationStatus
if #available(iOS 14, *) {
authorizationStatus = locationManager.authorizationStatus
} else {
authorizationStatus = CLLocationManager.authorizationStatus()
}
switch authorizationStatus {
case .restricted, .notDetermined:
locationManager.requestAlwaysAuthorization()
print("Restricted")
exit(0)
case .denied:
print("Denied")
case .authorizedAlways, .authorizedWhenInUse:
print("Authorized")
case .authorized:
print("Authorized")
@unknown default:
print("Unavailable")
}
}
}
/* -------- */
locationManager.startUpdatingLocation()
getGeoLocation()
autoreleasepool {
RunLoop.main.run()
}
I can use who -b but it will be the same to last shutdown. I am seeking for a API level to use with Swift.
Yeah, I ate the 1st line:
func listDir(dir: String) {
}
And I use to try some functions firstly in Playground before apply into the code. I will make a small test program to do that and let you know, thanks again.
Ok, this is my struct and the list, the real one:
struct Wifi: Codable {
var SSID: String
var bSSID: String
var Channel: Int
var Band: String
var Width: String
var noise: Int
var rssi: Int
var qualitySNR: Int
var isConnected: Bool
init() {
SSID = ""
bSSID = "00:00:00:00:00:00"
Channel = 0
Band = ""
Width = ""
rssi = 0
noise = 0
qualitySNR = 0
isConnected = false
}
}
var wifiList: [Wifi] = []
Here is how I do populate it:
wifiList.removeAll(keepingCapacity: false)
//... get all stuff from the network and insert into the list
// wifi is declared as wifi = Wifi.init()
wifiList.insert(wifi, at: 0)
After the list if completed I convert it string, as I showed before:
func convertToJSONString() -> String {
let encoder = JSONEncoder()
let data = try! encoder.encode(wifiList)
return String(data: data, encoding: .utf8)!
}
What I get:
[{"bSSID":"00:00:00:00:00:00","Band":"2Ghz","rssi":-77,"SSID":"CLARO_2GA37FE4","Channel":6,"isConnected":false,"Width":"40MHz","noise":76,"qualitySNR":-153},{"bSSID":"00:00:00:00:00:00","Band":"2Ghz","rssi":-74,"SSID":"2.4G DEMOLIDOR HELMAR LUAN","Channel":8,"isConnected":false,"Width":"40MHz","noise":76,"qualitySNR":-150},{"bSSID":"00:00:00:00:00:00","Band":"5Ghz","rssi":-88,"SSID":"TP-LINK_9562_5G","Channel":157,"isConnected":false,"Width":"80MHz","noise":76,"qualitySNR":-164},{"bSSID":"00:00:00:00:00:00","Band":"5Ghz","rssi":-77,"SSID":"AP 71 A-5G","Channel":52,"isConnected":false,"Width":"80MHz","noise":76,"qualitySNR":-153},{"bSSID":"00:00:00:00:00:00","Band":"5Ghz","rssi":-48,"SSID":"XIMA","Channel":157,"isConnected":true,"Width":"80MHz","noise":76,"qualitySNR":-124},{"bSSID":"00:00:00:00:00:00","Band":"5Ghz","rssi":-83,"SSID":"5.G DEMOLIDOR HELMAR LUAN","Channel":48,"isConnected":false,"Width":"80MHz","noise":76,"qualitySNR":-159},{"bSSID":"00:00:00:00:00:00","Band":"2Ghz","rssi":-61,"SSID":"LIMA_2G","Channel":10,"isConnected":false,"Width":"40MHz","noise":76,"qualitySNR":-137},{"bSSID":"00:00:00:00:00:00","Band":"2Ghz","rssi":-76,"SSID":"Net-Virtua-9095-2.4G","Channel":1,"isConnected":false,"Width":"40MHz","noise":76,"qualitySNR":-152},{"bSSID":"00:00:00:00:00:00","Band":"2Ghz","rssi":-84,"SSID":"#NET-CLARO-WIFI","Channel":1,"isConnected":false,"Width":"40MHz","noise":76,"qualitySNR":-160},{"bSSID":"00:00:00:00:00:00","Band":"2Ghz","rssi":-91,"SSID":"Renato.2G","Channel":11,"isConnected":false,"Width":"40MHz","noise":76,"qualitySNR":-167},{"bSSID":"00:00:00:00:00:00","Band":"5Ghz","rssi":-78,"SSID":"AP 71 A","Channel":52,"isConnected":false,"Width":"80MHz","noise":76,"qualitySNR":-154},{"bSSID":"00:00:00:00:00:00","Band":"2Ghz","rssi":-85,"SSID":"Vila Mariana","Channel":1,"isConnected":false,"Width":"40MHz","noise":76,"qualitySNR":-161}]
[{"bSSID":"00:00:00:00:00:00","Band":"5Ghz","rssi":-52,"SSID":"XIMA","Channel":157,"isConnected":false,"Width":"80MHz","noise":80,"qualitySNR":-132}]
In this example, the last item shouldn't be "out" of the array. The result shows like 2 arrays and I expect to have only one.
I will paste the full code, this is from Playground, now running on playground it won't separate the array, so I guess that can be related to the way I am doing in the real code, there it is called inside another function, so I think that I will enclosure it a thread and see what happens. The code below works fine.
Also, I know I can simply use wifiList.removeAll() instead of wifiList.removeAll(keepingCapacity: false), but as someone with little knowledgement in Swift I use that way to force me to learn about other options.
import Foundation
import CoreWLAN
class Discovery {
var currentInterface: CWInterface
var interfacesNames: [String] = []
var networks: Set<CWNetwork> = []
// Failable init using default interface
init?() {
if let defaultInterface = CWWiFiClient.shared().interface(),
let name = defaultInterface.interfaceName {
self.currentInterface = defaultInterface
self.interfacesNames.append(name)
self.findNetworks()
} else {
return nil
}
}
init(interfaceWithName name: String) {
self.currentInterface = CWWiFiClient().interface(withName: name)!
self.interfacesNames.append(name)
self.findNetworks()
}
// Fetch detectable WIFI networks
func findNetworks() {
do {
self.networks = try currentInterface.scanForNetworks(withSSID: nil)
} catch let error as NSError {
print("Error: \(error.localizedDescription)")
}
}
}
struct Wifi: Codable {
var SSID: String
var bSSID: String
var Channel: Int
var Band: String
var Width: String
var noise: Int
var rssi: Int
var qualitySNR: Int
var isConnected: Bool
init() {
SSID = ""
bSSID = "00:00:00:00:00:00"
Channel = 0
Band = ""
Width = ""
rssi = 0
noise = 0
qualitySNR = 0
isConnected = false
}
}
var wifiList: [Wifi] = []
func getWifiNetworks() {
var connectedNetwork = ""
wifiList.removeAll(keepingCapacity: false)
if let discovery = Discovery() {
var wifi: Wifi
let connectedNetwork = CWWiFiClient.shared().interface()!.ssid()!
for network in discovery.networks {
wifi = Wifi.init()
wifi.SSID = network.ssid?.description ?? ""
wifi.isConnected = wifi.SSID == connectedNetwork
wifi.bSSID = network.bssid?.description ?? "00:00:00:00:00:00"
wifi.Channel = network.wlanChannel?.channelNumber ?? 0
wifi.rssi = network.rssiValue
wifi.noise = network.noiseMeasurement
wifi.qualitySNR = wifi.rssi - wifi.noise
switch network.wlanChannel?.channelBand {
case .bandUnknown:
wifi.Band = "Unknown"
case .band2GHz:
wifi.Band = "2Ghz"
case .band5GHz:
wifi.Band = "5Ghz"
case .band6GHz:
wifi.Band = "6Ghz"
case .none:
wifi.Band = "Unknown"
case .some(_):
wifi.Band = "Unknown"
}
switch network.wlanChannel?.channelWidth {
case .width160MHz:
wifi.Width = "160MHz"
case .none:
wifi.Width = "none"
case .some(.widthUnknown):
wifi.Width = "Unknown"
case .some(.width20MHz):
wifi.Width = "20MHz"
case .some(.width40MHz):
wifi.Width = "40MHz"
case .some(.width80MHz):
wifi.Width = "80MHz"
case .some(_):
wifi.Width = "Unknown"
}
wifi.rssi = network.rssiValue
wifiList.insert(wifi, at: 0)
}
}
}
func convertWifiListToString() -> String {
let encoder = JSONEncoder()
let data = try! encoder.encode(wifiList)
return String(data: data, encoding: .utf8)!
}
getWifiNetworks()
let wifiListJson = convertWifiListToString()
print(wifiListJson)
Which type of func is it ? If async, it could be a concurrency issue.
Yes, it is async and after reading some of your questions I refactored some parts and seems to be working now. Anyway it's one of the expected weird behaviors when not dealing well with threads.
Thank you guys!