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
Changing Color of Button Text and State
Swift Property Observer in Protocol Extension
Swift Realm, Load the Pre-Populated Database the Right Way
Swift: How to Change a Property's Value Without Calling Its Didset Function
Cannot Read the Nfc Chip of the Epassport Using iOS13
How to Determine If a Variable Passed in Is Reference Type or Value Type
Read a File in a MACos Command Line Tool Project
Changing Value in Nested Dictionary in Swift
Where Is the .Camera Anchorentity Located
How to Benchmark Swift Code Execution
How Are Optional Values Implemented in Swift
Views Compressed by Other Views in Swiftui VStack and List
Uitableview - Multiple Selection and Single Selection
What Does <> (Angle Brackets) Do on Class Names in Swift
What Is an Example of Drawing Custom Nodes with Vertices in Swift Scenekit
Handle Swiftui and Corelocation with Mvvm-Pattern
How to Open Another Window in MACos in Swift with Cocoa
How to Read and Write Data to a Text File in Swift Using Playground