Issue with string

Hello!

I will show what is going on here with a very simple example:

var str: String
str = "Test"

func test(param: String) {
  print(param)
}

What is happening is: running this in my computer it shows: Test running in another Mac it shows: Optional("Test")

This is a simple code, but because of that "optional" the real code will give an error because of "Invalid character"

I tried wrap with String() String(describing: ) and I can't fix that. Any help on this?

Thanks

Replies

Where do you test ? In playground ? In an app ? In Terminal ?

.

I tried wrap with String() String(describing: )

What did you try exactly ?

You don't show how you use test func. Please show the complete code.

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.

running on the terminal

What do you mean ? Running on the Mac or running through Terminal utility ?

With what you showed, it is "impossible" to get the print you get.

Unless you wrote:

var str: String?
str = "Test"

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

Please show how myStruct is defined.

Is it?

var myStruct : MyStruct

If so, show MyStruct. Is it like this?

struct MyStruct {
  var theString : String?
  // other var
}

In addition, this does not make sense:

func(param: myStruct.theString)

Is it the way you are calling the func ? Then it should be

test(param: myStruct.theString)

So please, show real complete code.

  • Lol sure it's test(param: myStruct.theString)

Add a Comment

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

Could be the problem comes from:

loadConfiguration() // somewhere it reads the SQLite

I guess loadConfiguration is populating config ? How does it do it precisely ? Are you sure it updates config ? Are you sure you return String and not String?

Is config a global var ? Where is it defined exactly ? Inside a class ?

Note: I asked similar question for your other post and you never precisely answered. So it is really hard to help.

  • Maybe you are reading local value (ie, on you Mac)/ So, when you run on another machine, it cannot get the value ?

  • And at the client's computer it reads the data into the config, as I can print it's value and shows like Optional("endpoint.com") where mine shows only "endpoint", eg. The issue is that read data will break the program, seems like URLComponents() don´t like using Optional

Add a Comment

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\")"

You never answer questions precisely and completely, so that makes this discussion really unproductive. For sure the problem is in your code, so you need to show enough code so that we can tell you.

  • Could you show how you get data ?
  • Where do data come from ?
  • What is exactly in value ? Is it an optional ?

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!

So the point was that effectively your request returned nil…

Thank you for feed back. Lesson for future posts is that you should give enough context, not only a small chunk of code which you thought was the origin of error.

Good continuation, don't forget to close the thread (and others you may have opened).