How to Concatenate Optional Swift Strings

Proper way to concatenate optional swift strings?

compactMap would work well here, combined with .joined(separator:):

let f: String? = "jo"
let l: String? = "smith"

[f,l] // "jo smith"
.compactMap { $0 }
.joined(separator: " ")

It doesn't put the space between if one is nil:

let n: String? = nil

[f,n] // "jo"
.compactMap { $0 }
.joined(separator: " ")

How to concatenate optional String in SWIFT

In your case, it is pointless to declare the value empty, since you are modifying it in the next line.

However, if the assigning happens somewhere else and you want to use a variable with !, you should check whether the string has a value with ?. This will not be called if text is nil.

text? += "! How r you?"

Concatenate literal with Optional String

You can use the map method of Optional:

let username = name.map { "@" + $0 }

If name is nil then the closure is not executed and the result is nil. Otherwise the closure is evaluated with $0 set to the unwrapped name.

How can I concatenate multiple optional strings in swift 3.0?

Bug report filed by OP:

  • SR-1122: Failure to typecheck chain of binary operators on force-unwrapped values

Which has been resolved (fix commited to master Jan 3 2017), and should hence no longer be an issue in upcoming Swift 3.1.


This seems to be a bug (not present in Swift 2.2, only 3.0) associated with the case of:

  • Using the forced unwrapping operator (!) for at least 3 terms in an expression (tested using at least 2 basic operators, e.g. + or -).
  • For some reason, given the above, Swift messes up type inference of the expression (specifically, for the x! terms themselves, in the expression).

For all the examples below, let:

let a: String? = "a"
let b: String? = "b"
let c: String? = "c"

Bug present:

// example 1
a! + b! + c!
/* error: ambiguous reference to member '+' */

// example 2
var d: String = a! + b! + c!
/* error: ambiguous reference to member '+' */

// example 3
var d: String? = a! + b! + c!
/* error: cannot convert value of type 'String'
to specified type 'String?' */

// example 4
var d: String?
d = a! + b! + c!
/* error: cannot assign value of type 'String'
to specified type 'String?' */

// example 5 (not just for type String and '+' operator)
let a: Int? = 1
let b: Int? = 2
let c: Int? = 3
var d: Int? = a! + b! + c!
/* error: cannot convert value of type 'Int'
to specified type 'Int?' */
var e: Int? = a! - b! - c! // same error

Bug not present:

/* example 1 */
var d: String? = a! + b!

/* example 2 */
let aa = a!
let bb = b!
let cc = c!
var d: String? = aa + bb + cc
var e: String = aa + bb + cc

/* example 3 */
var d: String? = String(a!) + String(b!) + String(c!)

However as this is Swift 3.0-dev, I'm uncertain if this is really a "bug", as well as what's the policy w.r.t. reporting "bugs" in a not-yet-production version of code, but possibly you should file radar for this, just in case.

As for answering your question as how to circumvent this issue:

  • use e.g. intermediate variables as in Bug not present: Example 2 above,
  • or explicitly tell Swift all terms in the 3-term expression are strings, as in Bug not present: Example 3 above,
  • or, better yet, use safe unwrapping of your optional, e.g. using optional binding:

    var d: String? = nil
    if let a = a, b = b, c = c {
    d = a + b + c
    } /* if any of a, b or c are 'nil', d will remain as 'nil';
    otherwise, the concenation of their unwrapped values */

Swift prevent Optional() or nil in string concatenate result | Create query string from object

The best practice is to use the URLComponents and URLQueryItem structs.

This is my approach to solving your problem.

First I added an enum to avoid having hardcoded strings.

struct Request {
var page: Int
var name: String?
var favoriteName: String?
var favoriteId: Int?
}

enum RequestValues: String {
case page
case name
case favoriteName
case favoriteId
}

Then I made this helper function to return the non nil vars from the Request instance as an array of URLQueryItem.

func createQuery(request: Request) -> [URLQueryItem] {

var queryItems: [URLQueryItem] = []

queryItems.append(URLQueryItem(name: RequestValues.page.rawValue, value: "\(request.page)"))

if let name = request.name {
queryItems.append(URLQueryItem(name: RequestValues.name.rawValue, value: name))
}

if let favoriteName = request.favoriteName {
queryItems.append(URLQueryItem(name: RequestValues.favoriteName.rawValue, value: favoriteName))
}

if let favoriteId = request.favoriteId {
queryItems.append(URLQueryItem(name: RequestValues.favoriteId.rawValue, value: "\(favoriteId)"))
}

return queryItems
}

Then you can get the query string like this:

let queryString = queryItems.compactMap({ element -> String in
guard let value = element.value else {
return ""
}
let queryElement = "\(element.name)=\(value)"
return queryElement
})

this will give you the expected result in your question.

page=20&name=&favoriteName=&favoriteId=25

But you should use the URLComponents struct to build your url as such.

func buildURL() -> URL? {

var urlComponents = URLComponents()
urlComponents.scheme = "https"
urlComponents.host = "google.com"
urlComponents.queryItems = queryItems
urlComponents.path = "/api/example"
urlComponents.url

guard let url = urlComponents.url else {
print("Could not build url")
return nil
}

return url
}

This would will give you the url with the query.
It would look like this :

https://google.com/api/example?page=5&name=nil&favoriteName=Hello&favoriteId=9

Swift 3.0 String concatenation leaves Optional

In Swift 3 all properties of the native struct DateComponents are optionals unlike the Foundation NSDateComponents counterparts.

var year: Int? { get set }

You need to unwrap it. If you specified the unit year in ageComponents you can do that safely.

How do I concatenate strings in Swift?

You can concatenate strings a number of ways:

let a = "Hello"
let b = "World"

let first = a + ", " + b
let second = "\(a), \(b)"

You could also do:

var c = "Hello"
c += ", World"

I'm sure there are more ways too.

Bit of description

let creates a constant. (sort of like an NSString). You can't change its value once you have set it. You can still add it to other things and create new variables though.

var creates a variable. (sort of like NSMutableString) so you can change the value of it. But this has been answered several times on Stack Overflow, (see difference between let and var).

Note

In reality let and var are very different from NSString and NSMutableString but it helps the analogy.

How to concatenate an optional array to another array in Swift?

One of the arrays is optional. You have to handle the possible nil value somehow.

A simple solution using nil-coalescing:

let concatenated = var1 + (var2 ?? [])

or, slightly more complex:

var concatenated = var1

if let var2 = var2 {
concatenated.append(var2)
}

There are other possible solutions, of course.

How to concatenate unwrapped optional and string

Assuming baseURL and path are of type String

let baseURL = "http://10.150.160.170"
let path = "/welcome-page"
let urlString = baseURL + path
let url = URL(string: urlString)
let requestObj = URLRequest(url: url!)


Related Topics



Leave a reply



Submit