Convert Int to String in Swift and remove optional wrapping? - swift

I am attempting to convert Int? to a String and assign it to a label without including the optional text. I currently have:
struct Choice: Mappable{
var id: String?
var choice: String?
var questionId: String?
var correct: Bool?
var responses: Int?
init?(map: Map) {
}
mutating func mapping(map: Map) {
id <- map["id"]
questionId <- map["questionId"]
choice <- map["choice"]
correct <- map["correct"]
responses <- map["responses"]
}
}
In the class accessing it
var a:String? = String(describing: self.currentResult.choices?[0].responses)
print("\(a!)")
and the output is:
Optional(1)
How would I make it just output 1 and remove the optional text?

a is an Optional, so you need to unwrap it prior to applying a String by Int initializer to it. Also, b needn't really be an Optional in case you e.g. want to supply a default value for it for cases where a is nil.
let a: Int? = 1
let b = a.map(String.init) ?? "" // "" defaultvalue in case 'a' is nil
Or, in case the purpose is to assign the possibly existing and possibly String-convertable value of a onto the text property of an UILabel, you could assign a successful conversion to the label using optional binding:
let a: Int? = 1
if let newLabelText = a.map(String.init) {
self.label.text = newLabelText
}

Why don't?
let a : Int = 1
var b = "\(a)"
print(b)
so
$ swift
[ 9> let a : Int = 1
a: Int = 1
[ 10> var b = "\(a)"
b: String = "1"
[ 11> print(b)
1
By the way there are other options like this one
12> var c = a.description
c: String = "1"
13> print(c)
1

Related

How to return from a enum the correct type so can be used from a function in sample data

Im trying to tell my model to return a string for the enum type so I can set my image properly on the front end. I am quite new to swift and swift ui coming from a Csharp background.
struct PlayerRankingViewModel : Identifiable {
var id: UUID
var PlayerId : Int
var RankingType : Int
var RankingTypeImage : String
var FirstName:String
var LastName : String
var Reps: Decimal
var Weight: Decimal
var Seconds:Decimal
var DistanceFt:Decimal
var DistanceInches:Decimal
enum RankingTypes :Int{
case BAH = 1
case PU = 2
case TB = 3
case BP = 4
case OP = 5
case PUH = 6
case Bike = 7
case TwentyFiveYard = 8
case OneFiftyYard = 9
case Jumps = 10
case VJ = 11
case BroadJump = 12
case FrontSquat = 13
case HangClean = 14
}
init(id: UUID = UUID() ,PlayerId:Int,RankingType:Int,RankingTypeImage:String,
FirstName:String,LastName:String, Reps:Decimal,
Weight:Decimal,Seconds:Decimal,DistanceFt:Decimal,
DistanceInches:Decimal){
self.id = id
self.PlayerId = PlayerId
self.RankingType = RankingType
self.RankingTypeImage = ConvertExerciseTypeToImage(by: RankingType)
self.FirstName = FirstName
self.LastName = LastName
self.Reps = Reps
self.Weight = Weight
self.Seconds=Seconds
self.DistanceFt = DistanceFt
self.DistanceInches = DistanceInches
}
This Is function doing the conversation
func ConvertExerciseTypeToImage(by ExerciseType: Int) -> String {
if(ExerciseType == RankingTypes.Bike.rawValue)
{
return("bicycle")
}
}}
My Main Question is how do I pass that in my sample data section
extension PlayerRankingViewModel {
static var sampleData : [PlayerRankingViewModel] {
[
PlayerRankingViewModel(PlayerId:2,RankingType:RankingTypes.BP.rawValue,
RankingTypeImage What Do I put here?? : ,FirstName: "Dazy",
LastName:"Johnstone" ,Reps: 56.39, Weight:
125.00,Seconds:0.00,DistanceFt:0.00,DistanceInches:0.00)
]
As you see am not to sure how I place the value into the RankingTypeImage or is this the best way to achieve this should I just return an image. I guess am looking for best practise for type convertors, I come form a sharp background.
Its so on the front end I can display an image based on what exercise the student is doing?
You can do the conversion right in the enum
enum RankingTypes: Int {
case BAH = 1, PU, TB, BP, OP, PUH, Bike, TwentyFiveYard
case OneFiftyYard, Jumps, VJ, BroadJump, FrontSquat, HangClean
var stringValue : String {
switch self {
...
case .Bike: return "bicycle"
...
}
}
}
Please consider the Swift naming convention that variables, functions and enum cases start with a lowercase letter.
In the enum the subsequent integer values are inferred after specifying the first one

Shorter Alternative to ternary to generate empty string if nil?

I have a parameter of Type Double?.
When this parameter is nil, I want to have an empty string.
I can use if (variable == nil) ? "" : String(variable!) but is there a shorter alternative?
Using Optional.map and the nil-coalescing operator ?? you can do
var variable: Double? = 1.0
let string = variable.map { String($0) } ?? ""
The closure is called (and the string returned) if the variable is not nil, otherwise map returns nil and the expression evaluates to the empty string.
I don't see a simple way to simplify your code. An idea is to create a Double extension like this:
extension Optional where Wrapped == Double {
var asString: String {
self == nil ? "" : String(self!)
}
}
And then instead of that if condition you just use:
variable.asString
If you want to use the resulting string in another string, like this:
let string = "The value is: \(variable)"
and possibly specify what to print when variable is nil :
let string = "The value is: \(variable, nil: "value is nil")"
you can write a handy generic extension for String.StringInterpolation which takes any type of value and prints this and if it's an optional and also nil it prints the specified "default" string:
extension String.StringInterpolation {
mutating func appendInterpolation<T>(_ value: T?, `nil` defaultValue: #autoclosure () -> String) {
if let value = value {
appendLiteral("\(value)")
} else {
appendLiteral(defaultValue())
}
}
}
Example:
var d: Double? = nil
print("Double: \(d, nil: "value is nil")")
d = 1
print("Double: \(d, nil: "value is nil")")
let i = 1
print("Integer: \(i, nil: "value is nil")")
Output on the console:
Double: value is nil
Double: 1.0
Integer: 1
Just for fun a generic approach to cover all types that conforms to LosslessStringConvertible:
extension LosslessStringConvertible {
var string: String { .init(self) }
}
extension Optional where Wrapped: LosslessStringConvertible {
var string: String { self?.string ?? "" }
}
var double = Double("2.7")
print(double.string) // "2.7\n"
Property wrappers should help you give the desired result - property wrappers have a special variables wrappedValue and projectedValue that can add a layer of separation and allow you to wrap your custom logic.
wrappedValue - manipulate this variable with getters and setters. It has very less use in our case as it is of Double? type
projectedValue - this is going to be our focus as we can use this variable to project the Double as a String in our case.
The implementation is as below
#propertyWrapper
struct DoubleToString {
private var number: Double = 0.0
var projectedValue: String = ""
var wrappedValue: Double?{
get {
return number // Not really required
}
set {
if let value = newValue { // Check for nil
projectedValue = value.description // Convert to string
number = value
}
}
}
}
Now we create a struct which uses this wrapper.
struct NumbersTest {
#DoubleToString var number1: Double?
#DoubleToString var number2: Double?
}
On running the below code, we get the desired result. $number1 gives us the projectedValue and if we ignore the $ symbol we get the wrappedvalue
var numbersTest = NumbersTest()
numbersTest.number1 = 25.0
numbersTest.number2 = nil
print(numbersTest.$number1) //"25.0"
print(numbersTest.$number2) //""
By using property wrappers you can keep the variable interoperable to get both Double and String values easily.

String extension that adds a method "add" and takes an Int as a parameter with no label and returns an optional Int

I am trying to do string extension that adds a method "add" and takes an Int as a parameter with no label and returns an optional Int. If the string can be turned into an integer, return an integer with the string’s integer value plus the passed in value. If the string cannot be turned into an integer, return nil.
I wrote out the code below however I can't get it to work.
I get the following warning message for each value:
Immutable value 'value1' was never used; consider replacing with '_' or removing it
import UIKit
class MyViewController: UIViewController {
override func loadView() {
let value1: Int? = "5".add(3) // value1 will equal 8
let value2: Int? = "-2".add(1) // value2 will equal -1
let value3: Int? = "words".add(4) // value3 will be nil
}
}
extension String {
func add(_: Int) -> Int? {
guard let someString = Int(self) else {
return nil
}
return someString + someString
}
}
This is what the solution is supposed to be:
let value1: Int? = "5".add(3) // value1 will equal 8
let value2: Int? = "-2".add(1) // value2 will equal -1
let value3: Int? = "words".add(4) // value3 will be nil
The issue with your extension is that you forgot to name your method parameter func add(_ value: Int) -> Int? { and add it to the someString value. Btw name Ann integer as someString is misleading and Swift is a type inferred language. There is no need to explicitly set the resulting types in most situations:
extension String {
func add(_ value: Int) -> Int? {
guard let integer = Int(self) else {
return nil
}
return integer + value
}
}
let value1 = "5".add(3) // value1 will equal 8
let value2 = "-2".add(1) // value2 will equal -1
let value3 = "words".add(4) // value3 will be nil
To silent the warning about not using the values you can simply print them.

Swift: The proper way to initialize model class with a lot of properties

How do you initialize your classes/structs with a lot of properties?
This question could probably be asked without Swift context but Swift brings a flavour to it, so I add Swift tag in headline and tags.
Let's say you have a User class with 20 properties. Most of them should not be nil or empty. Let's assume these properties are not interdependent. Let's assume that 33% of it should be constant (let) by the logic of the class. Let's assume that at least 65% of them do not have meaningful default values. How would you design this class and initialize an instance of it?
So far I have few thoughts but none of it seems to be completely satisfactory to me:
put all of the properties linearly in the class and make huge init method:
class User {
// there is 20 properties like that
let id : String
let username : String
let email : String
...
var lastLoginDate : Date
var lastPlayDate : Date
// then HUUUUGE init
init(id: String,
username: String,
...
lastPlayDate: Date) {
}
}
try to group properties into sub types and deal with smaller inits separately
class User {
struct ID {
let id : String
let username : String
let email : String
}
struct Activity {
var lastLoginDate : Date
var lastPlayDate : Date
}
let id : ID
...
var lastActivity : Activity
// then not so huge init
init(id: ID,
...
lastActivity: Activity) {
}
}
another solution is to break requirements a bit: either declare some of the properties optional and set values after init or declare dummy default values and set normal values after init, which conceptually seems to be the same
class User {
// there is 20 properties like that
let id : String
let username : String
let email : String
...
var lastLoginDate : Date?
var lastPlayDate : Date?
// then not so huge init
init(id: String,
username: String,
email: String) {
}
}
// In other code
var user = User(id: "1", username: "user", email: "user#example.com"
user.lastLoginDate = Date()
Is there a nice paradigm/pattern how to deal with such situations?
You can try the builder pattern.
Example
class DeathStarBuilder {
var x: Double?
var y: Double?
var z: Double?
typealias BuilderClosure = (DeathStarBuilder) -> ()
init(buildClosure: BuilderClosure) {
buildClosure(self)
}
}
struct DeathStar : CustomStringConvertible {
let x: Double
let y: Double
let z: Double
init?(builder: DeathStarBuilder) {
if let x = builder.x, let y = builder.y, let z = builder.z {
self.x = x
self.y = y
self.z = z
} else {
return nil
}
}
var description:String {
return "Death Star at (x:\(x) y:\(y) z:\(z))"
}
}
let empire = DeathStarBuilder { builder in
builder.x = 0.1
builder.y = 0.2
builder.z = 0.3
}
let deathStar = DeathStar(builder:empire)
Example taken from here: https://github.com/ochococo/Design-Patterns-In-Swift
If you are looking for a bit more Java like solution, you can try something like this.
Alternative Example
final class NutritionFacts {
private let servingSize: Int
private let servings: Int
private let calories: Int
private let fat: Int
private let sodium: Int
private let carbs: Int
init(builder: Builder) {
servingSize = builder.servingSize
servings = builder.servings
calories = builder.calories
fat = builder.fat
sodium = builder.sodium
carbs = builder.carbs
}
class Builder {
let servingSize: Int
let servings: Int
private(set) var calories = 0
private(set) var fat = 0
private(set) var carbs = 0
private(set) var sodium = 0
init(servingSize: Int, servings: Int) {
self.servingSize = servingSize
self.servings = servings
}
func calories(value: Int) -> Builder {
calories = value
return self
}
func fat(value: Int) -> Builder {
fat = value
return self
}
func carbs(value: Int) -> Builder {
carbs = value
return self
}
func sodium(value: Int) -> Builder {
sodium = value
return self
}
func build() -> NutritionFacts {
return NutritionFacts(builder: self)
}
}
}
let facts = NutritionFacts.Builder(servingSize: 10, servings: 1)
.calories(value: 20)
.carbs(value: 2)
.fat(value: 5)
.build()
Example taken from: http://ctarda.com/2017/09/elegant-swift-default-parameters-vs-the-builder-pattern

swift How to cast from Int? to String

In Swift, i cant cast Int to String by:
var iString:Int = 100
var strString = String(iString)
But my variable in Int? , there for error: Cant invoke 'init' with type '#Ivalue Int?'
Example
let myString : String = "42"
let x : Int? = myString.toInt()
if (x != null) {
// Successfully converted String to Int
//And how do can i convert x to string???
}
You can use string interpolation.
let x = 100
let str = "\(x)"
if x is an optional you can use optional binding
var str = ""
if let v = x {
str = "\(v)"
}
println(str)
if you are sure that x will never be nil, you can do a forced unwrapping on an optional value.
var str = "\(x!)"
In a single statement you can try this
let str = x != nil ? "\(x!)" : ""
Based on #RealMae's comment, you can further shorten this code using the nil coalescing operator (??)
let str = x ?? ""
I like to create small extensions for this:
extension Int {
var stringValue:String {
return "\(self)"
}
}
This makes it possible to call optional ints, without having to unwrap and think about nil values:
var string = optionalInt?.stringValue
If you need a one-liner it can be achieved by:
let x: Int? = 10
x.flatMap { String($0) } // produces "10"
let y: Int? = nil
y.flatMap { String($0) } // produces nil
if you need a default value, you can simply go with
(y.flatMap { String($0) }) ?? ""
EDIT:
Even better without curly brackets:
y.flatMap(String.init)
Apple's flatMap(_:) Documentation
Optional Int -> Optional String:
If x: Int? (or Double? - doesn't matter)
var s = x.map({String($0)})
This will return String?
To get a String you can use :
var t = s ?? ""
Hope this helps
var a = 50
var str = String(describing: a)
Crude perhaps, but you could just do:
let int100 = 100
println(int100.description) //Prints 100
Sonrobby, I believe that "Int?" means an optional int. Basically, by my understanding, needs to be unwrapped.
So doing the following works fine:
let y: Int? = 42
let c = String(y!)
That "!" unwraps the variable. Hope this helps!
As rakeshbs mentioned, make sure the variable won't be nill.
You need to "unwrap" your optional in order to get to the real value inside of it as described here. You unwrap an option with "!". So, in your example, the code would be:
let myString : String = "42"
let x : Int? = myString.toInt()
if (x != null) {
// Successfully converted String to Int
// Convert x (an optional) to string by unwrapping
let myNewString = String(x!)
}
Or within that conditional, you could use string interpolation:
let myNewString = "\(x!)" // does the same thing as String(x!)
For preventing unsafe optional unwraps I use it like below as suggested by #AntiStrike12,
if let theString = someVariableThatIsAnInt {
theStringValue = String(theString!))
}
Swift 3:
var iString:Int = 100
var strString = String(iString)
extension String {
init(_ value:Int){/*Brings back String() casting which was removed in swift 3*/
self.init(describing:value)
}
}
This avoids littering your code with the verbose: String(describing:iString)
Bonus: Add similar init methods for commonly used types such as: Bool, CGFloat etc.
You can try this to convert Int? to string
let myString : String = "42"
let x : Int? = myString.toInt()
let newString = "\(x ?? 0)"
print(newString) // if x is nil then optional value will be "0"
If you want an empty string if it not set (nil)
extension Int? {
var stringValue:String {
return self == nil ? "" : "\(self!)"
}
}