How get value from variables of similar names [duplicate] - swift

This question already has an answer here:
Swift, get variable name from a string
(1 answer)
Closed 6 years ago.
Sequential variable names defined. I want to reach a variable relative to the corresponding value.
var code = 2 // 5, 6, ... // corresponding values
var name : String
var name1 : String = "Aaaaaa"
var name2 : String = "Bbbbbb"
// var name3
// var name4 ...
name = "name" + String(code) // name = "Bbbbb" ??
I do not get the results I wanted.
I hope i explained correctly. Thank you for your help.

Unlike in Objective-C, you can't access a variable by a String of its name in Swift. In your case, you might want to just use an array:
var code = 2 // 5, 6, ... // corresponding values
var names = ["Aaaaaa", "Bbbbbb"]
var name = names[code - 1] // "Bbbbbb"
If you really want to do it dynamically from a string name, you'll have to bridge to Objective-C, for example:
class SomeObject: NSObject {
var name1 : String = "Aaaaaa"
var name2 : String = "Bbbbbb"
func getName(code: Int) -> String {
let name = valueForKey("name" + String(code)) as! String // "Bbbbbb"
return name
}
}
SomeObject().getName(2) // "Bbbbbb"
Of course, by doing this, you lose a lot of the safety that Swift provides.

Related

[Swift[ How to iterate over all the properties of an object

I have an object defined with about 15 properties. I am trying to iterate over all of the properties that aren't equal to zero and are of type Int or Double. Something like this:
/*
object.price1 = 10.0
object.price2 = 9.9
object.price3 = 8.9
object.price4 = 10.1
object.name = "banana"
object.type = "fruit"
object.quantitySold = 0
object.dateIntroduced = ""
*/
let banana = object()
for property in banana {
object.property = property*2
}
Any ideas on how to accomplish this?
This isn't an easy thing to do in Swift (although possible), but that's no bad thing: being able to iterate over an object's properties and mutate (change) them without having to directly reference a property by name could easily lead to some confusion for you or another developer later on, when you're trying to find out why a property of an object has changed.
Much better instead to make this kind of operation explicit, and name it correctly. Something like the following:
extension Object {
func doubledPrice() -> Object {
return Object(
price1: price1 * 2,
price2: price2 * 2,
price3: price3 * 2,
price4: price4 * 2,
name: name, //we can't double a string
type: type,
quantitySold: quantitySold, //I've named the func assuming you won't double the quantitySold, obviously if that's not the desired behaviour then this needs to change
dateIntroduced: dateIntroduced //can't double a date
)
}
}
Make the prices an array? This is from my phone so check for errors. The bad side to this is how messy it can be and how difficult it would be to keep organized.
class MyProduct{
var price1 : Int
var price2 : Int
var price3 : Int
var pricesArray : [Int]
init(price1 : Int, price2 : Int, price3 : Int, pricesArray : [Int]){
self.price1 = price1
self.price2 = price2
self.price3 = price3
for i in 0...2
{ pricesArray.append(0)}
pircesArray[0] = price1
pricesArray[1] = price2
pricesArray[2] = price3
self.pricesArray = pricesArray
}_
//then to go over it like
for i in 0...3{
banana.pricesArray[i] = banana.procesArray[i] * 2
}
Or you could make a function in the product class
func equate( sum : Int)
{
yourVar = yourVar * sum
}

How to create a pointer in Swift?

I'm working with Swift 3.
I would like to have this C syntax :
int myVar;
int *pointer = &myVar;
So modifying pointer or myVar does the same exact same thing.
Also I don't know if it makes any difference, but in my case myVar is an array containing elements of a class and pointer is a pointer to one element of this array.
The & also exists in Swift but can only be used as part of a parameter list (e.g. init, func, closure).
var i = 5
let ptr = UnsafeMutablePointer(&i)
print(ptr.pointee) // 5
// or
let ptr = UnsafeMutablePointer<Int>.allocate(capacity: 1)
ptr.initialize(to: 5)
// or with a closure
let ptr: UnsafePointer = { $0 }(&i)
(Assuming I understand what you're asking for....)
Try the following code in a playground. It should print "99" three times.
class Row {
var rowNumber = 0
}
var rows = [Row]()
let testRow = Row()
testRow.rowNumber = 1
rows.append(testRow)
let selectedRow = rows[0]
selectedRow.rowNumber = 99
print(testRow.rowNumber)
print(selectedRow.rowNumber)
print(rows[0].rowNumber)
By default, there's no copying of objects as part of an assignment statement. If it were a struct, that would be different.
Adding a bit for completeness:
If you want a similar effect with scalar values instead of objects, Swift supplies various types of wrappers.
let intPointer = UnsafeMutablePointer<Int>.allocate(capacity: 8) // Should be 1, not 8 according to comment re: docs
let other = intPointer
other.pointee = 34
print(intPointer.pointee)
(Warning: I haven't used these wrappers for anything except experimenting in a playground. Don't trust it without doing some research.)
Same example as #Phillip. But I used struct. In this example rows[0] won't change:
struct Row {
var rowNumber = 0
}
var rows = [Row]()
var testRow = Row()
testRow.rowNumber = 1
rows.append(testRow)
var selectedRow = rows[0]
selectedRow.rowNumber = 99
print(testRow.rowNumber) // prints 1
print(selectedRow.rowNumber) // prints 99
print(rows[0].rowNumber) // prints 1
There are no C style pointers (Unsafe Pointer) as the question asks however objects are shared by reference and structures are by value:
Swift assign, pass and return a value by reference for reference type and by copy for Value Type
structures are always copied when they are passed around in your code, but classes are passed by reference.
For example
How to have pointers/ references to objects
class Song {
init(title: String, image: String, file: String, volume: Float, queuePlayer: AVQueuePlayer, playerLooper: AVPlayerLooper?) {
self.title = title
self.image = image
...
}
var title: String
var image: String
...
}
var aSong = Song(title: "", image: "", ...)
var arrOfSongReferences: [Song] = [Song]()
arrOfSongReferences.append(aSong)
var ptrToASong: Song = aSong
aSong = nil
// Due to Swift garbage collection ARC (Automatic Reference Counting), we still have references to the original aSong object so it won't be deleted
If data is struct you cannot do this
struct Song {
var title: String
var image: String
...
}
var aSong: Song = Song(title: "", image: "", ...)
var copyOfASong: Song = aSong
Method
You can also pass by reference into a function
// this would be inside a class, perhaps Player. It doesn't have to be a static btw
static func playSound(_ sound: inout Song, volume: Float = 0.0) {
if (sound.playerLooper == nil) {
...
}
}
// usage
Player.playSound(sound: &aSong)

Optional value in swift 3 Optimised way

I have create class Testing model which has 4 dataMember it should not be null when accessing (means return default value)
extension Double {
/// Rounds the double to decimal places value
func roundTo(places:Int = 2) -> Double
{
let divisor = pow(10.00, Double(places))
return (self * divisor).rounded() / divisor
}
}
class TestingModel{
var id : String!
var name : String! = "abc" /*It is not working*/
var price : Double! = 0.00
var uniqueId : Int! = 1
/**
* Instantiate the instance using the passed dictionary values to set the properties values
*/
init(dictionary: [String:Any])
{
id = (dictionary["id"] as? String) ?? "" //I dont want to do like this way
name = dictionary["name"] as? String
price = (dictionary["price"] as? Double)?.roundTo() ?? 0.00
uniqueId = dictionary["unique_id"] as? Int
}
}
let t:TestingModel = TestingModel.init(dictionary: ["x id" : "x012y12345z45","x name":"test1","x price":100.0,"uniqueId":1236.0])
let testString = "Jd " + t.id
print(testString) //Perfect
print(t.name)
print(t.price) /* Only one decemal point is printed */
Getting Output
Jd
nil
0.0
Expected output
Jd
abc /Should return abc instead of nil/
0.00 /Two decimal point complulsury/
What i actually mean in
if i assign nil value to variable then it should remain with its default value without writing this Optional chaining ?? "abc" in constructor
price is a Double type and what you are asking to do is to print that double value to 2 decimal places. Then you should make use of the following.
let a = 0.0
print(String(format: "%.2f", a))
this prints:
0.00
If you are planning to round it to decimal places, then also the above code will return that. But if you need it to round and return a double type then you can check this answer
Based on your updated question, I suggest to use the model as follows:
class TestingModel{
var id : String = ""
var name : String = "abc"
var price : Double = 0.0
var uniqueId : Int = 1
/**
* Instantiate the instance using the passed dictionary values to set the properties values
*/
init(dictionary: [String:Any])
{
id = (dictionary["id"] as? String) ?? ""
name = dictionary["name"] as? String ?? "abc"
price = (dictionary["price"] as? Double) ?? 0.0
uniqueId = dictionary["unique_id"] as? Int ?? 1
}
}
You seem to have asked two different questions here. The first one regarding doubles have already been answered by adev. I will answer the second one, which is:
if i assign nil value to variable then it should remain with its default value without writing this Optional chaining ?? "abc" in constructor
If you want to do this then it means that the variable shouldn't be optional at all, as nil isn't one of its valid values. Make the variable a non-optional type and give it a default value.
class TestingModel{
var id : String = ""
var name : String = "abc"
var price : Double = 0.00
var uniqueId : Int = 1
}
You can't really avoid using ?? in the constructor because of the nature of dictionaries. They will always return a nil value if the key does not exist. You have to check it. It does not make sense even if this is possible anyway. Imagine something like this:
someVariable = nil // someVariable is now 0
This is extremely confusing. someVariable is 0, even though it appears that nil is assigned to it.
A workaround will be to add a dictionary extension. Something like this:
extension Dictionary {
func value(forKey key: Key, defaultValue: Value) -> Value {
return self[key] ?? defaultValue
}
}
But I still recommend that you use ?? instead.

Dynamic Struct creation in Swift - based on user input

I am trying to create dynamic struct in swift based on user input.
struct Diagnosis {
var diagName = String() // Name of the diagnosis
var diagSymptoms = [String]() // Symptoms of the diagnosis in a ranked array to identify prevelancy
var diagSpecialization = [String]() // the specializations which would mostly encounter this diagnosis
var diagRank = Int() // the overall rank of the diagnosis
var diagSynonoms = [String]() // the other name thru which the same diagnosis is called / referred.
// func init(diagName: String(),diagSymptoms: [String](),diagSpecialization: [String](),diagSynonoms: [String]())
init( let pasdiagName: String,let pasdiagSymptoms:Array<String>) {
self.diagName = pasdiagName
self.diagSymptoms = pasdiagSymptoms
}
}
var maleria = Diagnosis(pasdiagName: "Maleria",pasdiagSymptoms: ["fever","chill","body pain"])
The above creates the structure maleria - But in future I want to have the input from user and create a structure for that inputted string
var abc = "typhoid"
let valueof(abc) = Diagnosis()
The value of function is something I just put here arbitrarily to make my explanation clear.
I know I could do this in python and I am new to swift. Thanks in advance for the help.
As #Wain suggested, you should use a Dictionary.
This is how you create a mutable dictionary where the key is a String and the value can be any type.
var dict = [String:Any]()
This is how you put key/value pairs into the dictionary
dict["year"] = 2016
dict["word"] = "hello"
dict["words"] = ["hello", "world"]
And this is how you extract a value and use it
if let word = dict["word"] as? String {
print(word) // prints "hello"
}

Append use in swift

Why the code bellow does not change the string?
class Person {
var name = "Chris"
var age = 12
var male = true
var details, = [true, 100 , "good"]
}
family().details.append("friendly")
family().details //prints [1, 100, "good"]
Because you're accessing two different objects:
family().me.append("friendly")
This line creates an object, appending "friendly" to your [Any]
family().me //prints [1, 100, "good"]
Here you're printing the contents of a brand new object: me contains only 3 elements
If you want to see the change use the same object like so:
let f = family()
f.me.append("friendly")
f.me