Cannot convert value of type 'String' to expected argument type 'DefaultStringInterpolation' - swift5

I upgraded my swift 4.2 application to Swift 5 and I get this error. Does anyone know how to fix?
File using: GMStepper.swift
Error: Cannot convert value of type 'String' to expected argument type 'DefaultStringInterpolation'
if self.showIntegerIfDoubleIsInteger && floor(self.value) == self.value {
label.text = String(stringInterpolation: "\(Int(self.value))\(self.suffixString)")
} else {
label.text = String(stringInterpolation: "\(Int(self.value))\(self.suffixString)")
}

You should do like this :
if self.showIntegerIfDoubleIsInteger && floor(self.value) == self.value {
let intValue = Int(self.value)
label.text = String(stringInterpolation: "\(intValue)\(self.suffixString)")
} else {
let intValue = Int(self.value)
label.text = String(stringInterpolation: "\(intValue))\(self.suffixString)")
}

You should not call String.init(stringInterpolation:) directly.
init(stringInterpolation:)
Discussion
Do not call this initializer directly. It is used by the compiler when you create a string using string interpolation. Instead,
use string interpolation to create a new string by including values,
literals, variables, or expressions enclosed in parentheses, prefixed
by a backslash (\(…)).
Why don't you simply write your code as:
if self.showIntegerIfDoubleIsInteger && floor(self.value) == self.value {
label.text = "\(Int(self.value))\(self.suffixString)"
} else {
label.text = "\(Int(self.value))\(self.suffixString)"
}

Related

How to get the First Character in a name

I have below func in my class.
static func getFirstCharInName(strName: String) -> String {
let firstCharInName = String(strName.first)
return firstCharInName.trim()
}
I encountered this err:
Value of optional type 'Character?' must be unwrapped to a value of type 'Character'
What seems to be the problem?
Thanks
func getFirstCharInName(strName: String) -> String {
let indexStartOfText = strName.index(strName.startIndex, offsetBy: 0)
let indexEndOfText = strName.index(strName.startIndex, offsetBy: 0)
let firstChar = String(strName[indexStartOfText...indexEndOfText])
return firstChar
}
This error means that the expression has optional value (the value can be nil) that is not yet unwrapped, strName.first returns an optional value of Character?, but your function demands a returning type of String which is not an optional type.
So, in order to fix this, you need to unwrap the optional value strName.first, it seems like you are not familiar with optionals, here's the code for your case (choose one from two options):
func getFirstCharInName(strName: String) -> String {
// option 1: force unwrap - can cause fatal error
return String(strName.first!)
// option 2: optional binding
if let firstCharInName = strName.first {
return String(firstCharInName)
} else {
// if the optional value is nil, return an empty string
return ""
}
}
PS. I don't really understand the function trim() in your question, but if you mean to strip away the blank spaces like " ", you can do:
firstCharInName.trimmingCharacters(in: .whitespaces)
Avoid the optional simply with prefix, it's totally safe. if there is no first character you'll get an empty string.
static func getFirstChar(in name: String) -> String { // the function name getFirstChar(in name is swiftier
return String(name.prefix(1))
}
I don't know what the trim function is supposed to do.
It means that value of optional type 'Character?' (as result of your part of code strName.first) must be unwrapped to a value of type 'Character' before you will be gonna cast it to String type.
You may use this variant:
func getFirstCharInName(strName: String) -> String {
return strName.count != 0 ? String(strName.first!) : ""
}
As you can see, the exclamation point is in the string strName.first! retrieves the optional variable as it was needed.
you can do something like that:
extension String {
var firstLetter: String {
guard !self.isEmpty else { return "" }
return String(self[self.startIndex...self.startIndex])
}
}
then
let name = "MilkBottle"
let first = name.firstLetter // "M"

Convert optional string to Int crashes in spite of having value

I check the optional string
print(limitCash)
if let value = Int32(limitCash) {
aProvider.limitBuy = value
}
The value of limitCash is Optional("500").
The program checks if let statement and skips it without assigning value.
Program crashes if I try aProvider.limitBuy = Int32(limitCash)!
First you need to unwrap String? to String and then unwrap the result of casting from String to UInt32 (that will be Uint32?).
print(limitCash)
if let stringValue = limitCash {
if let value = Int32(stringValue) {
print(value) // 500
}
}

Swift string from optional Double

Is there a shortcut to specify placeholder text when the value is nil in Swift?
Right now I do:
let myText:String!
if myDouble != nil{
myText = "\(myDouble!)"
}else{
myText = "Value not provided"
}
That works, but it's very annoying to have to do that all the time. Is there a way to do something like
let myText:String = "\(myDouble ?? "Value no provided")"
That fails because it wants a default Double value, but I really want a String value.
You can use map and nil-coalescing:
let myText = myDouble.map { String($0) } ?? "Value not provided"
If myDouble is nil, the result of map is nil and the result is the value after the ??.
If myDouble is not nil, the result is the output of the map which creates a string from the Double.
For more details, please see the documentation for the map function of the Optional enumeration in the Swift standard library.
It seems reasonable to do
let myDouble: Double? = Double(3.0)
let myText = myDouble?.description ?? "Value not provided"
If myDouble is nil, then myText is "Value not provided". If myDouble is not nil, it's assigned the string representation of the number.
I think good approach to this is to make Extension to optional where Double is the Wrapped element:
extension Optional where Wrapped == Double {
var stringValue: String {
guard let me = self else { return "No Value Provided" }
return "\(me)"
}
}
// Use it like this:
myDouble.stringValue
Another approach could be making your custom operator like this:
public func ??(rhd: Double?, lhd: String) -> String {
if let unwrapped = rhd {
return String(unwrapped)
} else {
return lhd
}
}
And now your line let myText:String = "\(myDouble ?? "Value no provided")" works.
Please let me now if you don' understand anything.
This should work:
let myText = myDouble != nil ? String(myDouble!) : "Value not provided"

Value of type 'String' has no member indices

I am trying to migrate my Swift 2.2 code to Swift 3(beta) and I am getting the following error in the below code after migrating to Swift 3.0 ,"Value of type 'String' has no member indices"
Would require help on the following were routePathComponent is a String.
After Migrating
if routePathComponent.hasPrefix(":") {
let variableKey = routePathComponent.substring(with: routePathComponent.indices.suffix(from: routePathComponent.characters.index(routePathComponent.startIndex, offsetBy: 1)))
}
Before Migrating
if routePathComponent.hasPrefix(":") {
let variableKey = routePathComponent.substringWithRange(routePathComponent.startIndex.advancedBy(1)..<routePathComponent.endIndex)
let variableValue = component.URLDecodedString()
if variableKey.characters.count > 0 && variableValue.characters.count > 0 {
variables[variableKey] = variableValue
}
}
If you want to omit the first character if it's a colon, that's the Swift 3 way
if routePathComponent.hasPrefix(":") {
let variableKey = routePathComponent.substring(from: routePathComponent.index(after :routePathComponent.startIndex))
}
The equivalent of your other example in the comment is
if let endingQuoteRange = clazz.range(of:"\"") {
clazz.removeSubrange(endingQuoteRange.upperBound..<clazz.endIndex)
...
}
You can use dropFirst() if you want just drop first character from String.
if routePathComponent.hasPrefix(":") {
let variableKey = String(routePathComponent.characters.dropFirst())
}
indices is property of Collection types. String is not Collection since v.2.3.
Use .characters property, which returns Collection of characters of the String.
var routePathComponent = ":Hello playground"
if routePathComponent.hasPrefix(":") {
let variableKey = routePathComponent.substringFromIndex(routePathComponent.startIndex.advancedBy(1))
//print(variableKey)
}
This should do the trick

Check empty string in Swift?

In Objective C, one could do the following to check for strings:
if ([myString isEqualToString:#""]) {
NSLog(#"myString IS empty!");
} else {
NSLog(#"myString IS NOT empty, it is: %#", myString);
}
How does one detect empty strings in Swift?
There is now the built in ability to detect empty string with .isEmpty:
if emptyString.isEmpty {
print("Nothing to see here")
}
Apple Pre-release documentation: "Strings and Characters".
A concise way to check if the string is nil or empty would be:
var myString: String? = nil
if (myString ?? "").isEmpty {
print("String is nil or empty")
}
I am completely rewriting my answer (again). This time it is because I have become a fan of the guard statement and early return. It makes for much cleaner code.
Non-Optional String
Check for zero length.
let myString: String = ""
if myString.isEmpty {
print("String is empty.")
return // or break, continue, throw
}
// myString is not empty (if this point is reached)
print(myString)
If the if statement passes, then you can safely use the string knowing that it isn't empty. If it is empty then the function will return early and nothing after it matters.
Optional String
Check for nil or zero length.
let myOptionalString: String? = nil
guard let myString = myOptionalString, !myString.isEmpty else {
print("String is nil or empty.")
return // or break, continue, throw
}
// myString is neither nil nor empty (if this point is reached)
print(myString)
This unwraps the optional and checks that it isn't empty at the same time. After passing the guard statement, you can safely use your unwrapped nonempty string.
In Xcode 11.3 swift 5.2 and later
Use
var isEmpty: Bool { get }
Example
let lang = "Swift 5"
if lang.isEmpty {
print("Empty string")
}
If you want to ignore white spaces
if lang.trimmingCharacters(in: .whitespaces).isEmpty {
print("Empty string")
}
Here is how I check if string is blank. By 'blank' I mean a string that is either empty or contains only space/newline characters.
struct MyString {
static func blank(text: String) -> Bool {
let trimmed = text.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
return trimmed.isEmpty
}
}
How to use:
MyString.blank(" ") // true
You can also use an optional extension so you don't have to worry about unwrapping or using == true:
extension String {
var isBlank: Bool {
return self.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
}
}
extension Optional where Wrapped == String {
var isBlank: Bool {
if let unwrapped = self {
return unwrapped.isBlank
} else {
return true
}
}
}
Note: when calling this on an optional, make sure not to use ? or else it will still require unwrapping.
To do the nil check and length simultaneously
Swift 2.0 and iOS 9 onwards you could use
if(yourString?.characters.count > 0){}
isEmpty will do as you think it will, if string == "", it'll return true.
Some of the other answers point to a situation where you have an optional string.
PLEASE use Optional Chaining!!!!
If the string is not nil, isEmpty will be used, otherwise it will not.
Below, the optionalString will NOT be set because the string is nil
let optionalString: String? = nil
if optionalString?.isEmpty == true {
optionalString = "Lorem ipsum dolor sit amet"
}
Obviously you wouldn't use the above code. The gains come from JSON parsing or other such situations where you either have a value or not. This guarantees code will be run if there is a value.
Check check for only spaces and newlines characters in text
extension String
{
var isBlank:Bool {
return self.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()).isEmpty
}
}
using
if text.isBlank
{
//text is blank do smth
}
Swift String (isEmpty vs count)
You should use .isEmpty instead of .count
.isEmpty Complexity = O(1)
.count Complexity = O(n)
isEmpty does not use .count under the hood, it compares start and end indexes startIndex == endIndex
Official doc Collection.count
Complexity: O(1) if the collection conforms to RandomAccessCollection; otherwise, O(n), where n is the length of the collection.
Single character can be represented by many combinations of Unicode scalar values(different memory footprint), that is why to calculate count we should iterate all Unicode scalar values
String = alex
String = \u{61}\u{6c}\u{65}\u{78}
[Char] = [a, l, e, x]
Unicode text = alex
Unicode scalar values(UTF-32) = u+00000061u+0000006cu+00000065u+00000078
1 Character == 1 extended grapheme cluster == set of Unicode scalar values
Example
//Char á == extended grapheme cluster of Unicode scalar values \u{E1}
//Char á == extended grapheme cluster of Unicode scalar values \u{61}\u{301}
let a1: String = "\u{E1}" // Unicode text = á, UTF-16 = \u00e1, UTF-32 = u+000000e1
print("count:\(a1.count)") //count:1
// Unicode text = a, UTF-16 = \u0061, UTF-32 = u+00000061
// Unicode text = ́, UTF-16 = \u0301, UTF-32 = u+00000301
let a2: String = "\u{61}\u{301}" // Unicode text = á, UTF-16 = \u0061\u0301, UTF-32 = u+00000061u+00000301
print("count:\(a2.count)") //count:1
For optional Strings how about:
if let string = string where !string.isEmpty
{
print(string)
}
if myString?.startIndex != myString?.endIndex {}
I can recommend add small extension to String or Array that looks like
extension Collection {
public var isNotEmpty: Bool {
return !self.isEmpty
}
}
With it you can write code that is easier to read.
Compare this two lines
if !someObject.someParam.someSubParam.someString.isEmpty {}
and
if someObject.someParam.someSubParam.someString.isNotEmpty {}
It is easy to miss ! sign in the beginning of fist line.
public extension Swift.Optional {
func nonEmptyValue<T>(fallback: T) -> T {
if let stringValue = self as? String, stringValue.isEmpty {
return fallback
}
if let value = self as? T {
return value
} else {
return fallback
}
}
}
What about
if let notEmptyString = optionalString where !notEmptyString.isEmpty {
// do something with emptyString
NSLog("Non-empty string is %#", notEmptyString)
} else {
// empty or nil string
NSLog("Empty or nil string")
}
You can use this extension:
extension String {
static func isNilOrEmpty(string: String?) -> Bool {
guard let value = string else { return true }
return value.trimmingCharacters(in: .whitespaces).isEmpty
}
}
and then use it like this:
let isMyStringEmptyOrNil = String.isNilOrEmpty(string: myString)