i have a class UserContact which have an enum in the constructor
class UserContact( val uuid: Int ,
var phone: String ,
var sms: Boolean ,
var pushNotification: Boolean ,
var deviceType: UserDeviceType , // Enum
var jabberID: String ){
}
now i want to write an auxiliary constructor in this class but i dont know how to give default value for the enum
i have tried with "_" but it did not work
def this(){
this(0, "", false , false , _ , "")
}
please help
You need to put in some actual value. Just look at UserDeviceType values and choose which one you want in this constructor. But you should think if you really want an auxiliary constructor like this; it looks like a bad design in most circumstances, as Peter Neyens' comments explain.
The "default" value produced by var x: SomeEnumType = _ is null, same as for any object type (including String), but this is rarely what you want (it should only be used if the variable is guaranteed to be initialized later).
Related
I know the below is possible in Javascript. Is there anything similar I can use in SwiftUI to pass an object property as a String?
var a = { foo: 123 };
a.foo // 123
a['foo'] // 123
var str = 'foo';
a[str] // 123
What you likely want here is a key path. For example, given:
struct A {
var foo: Int
}
You can construct an A, and access it:
let a = A(foo: 123)
a.foo // 123
And given that, you can access the foo property by key path:
let kp = \A.foo
a[keyPath: kp] // 123
If your actual goal is to map strings to integer, that's just a [String: Int], and it would work identically. If you mean "I want to pass strings to objects has have fairly random things happen, and possibly crash like they do in JavaScript," then that's also possible, using a custom subscript like subscript(key: String) -> Int?.
My code:
open class Club(name: String, country: String)
class FemaleClub(): Club()
var femaleClub = FemaleClub("Blue", "Australia")
Why is the above code not possible?
Why does it have the error
no value passed for parameter name
and
no value passed for parameter country
in my subclass? The values are set when I initiate femaleClub.
In your example parent class Club has primary constructor which is, by language specification, must be called either from secondary constructors of the same class or primary constructor of subclasses to initialize parameters defined in primary constructor. If you don't want to call a primary constructor of a parent class from subclasses you have a couple of options:
Set default values to parameters of primary constructor:
open class Club(name: String = "DefaultName", country: String = "Country") {
}
In this case you will not be able to call primary constructor with params:
// this is not possible
var femaleClub = FemaleClub("Blue", "Australia")
Create secondary constructor in parent class which calls primary constructor:
open class Club(name: String, country: String) {
constructor(): this("Name", "Country")
}
But also you won't be able to call FemaleClub("Blue", "Australia").
To be able to call constructor with parameters of a subclass FemaleClub("Blue", "Australia") you need explicitly define them in primary constructor of the subclass and call parent's primary constructor, i.e.:
class FemaleClub(name: String, country: String): Club(name, country) {}
There are some problems with your code:
FemaleClub does not have a constructor which accepts two arguments, even if the base class has one.
The primary constructor of the inherited class should call the primary constructor of the base class. Because your base class accepts two non-nullable arguments, you have to provide them to it, otherwise your code wont compile.
These issues can be fixed in the following way:
class FemaleClub(name: String, country: String): Club(name, country) {
}
About Kotlin classes and inheritance, read here Classes and Inheritance and here Kotlin Inheritance.
You can use at least four approaches to get what you want:
First approach (default values):
open class Club(var name: String = "Blue", var country: String = "Australia") { }
public class FemaleClub(): Club() { }
fun main() {
var femaleClub = FemaleClub()
println("RESULT: ${femaleClub.country}")
}
// RESULT: Australia
Second approach (passing values):
open class Club(var name: String, var country: String) { }
class FemaleClub(): Club("Green", "NZ") { }
fun main() {
var femaleClub = FemaleClub()
println("RESULT: ${femaleClub.country}")
}
// RESULT: NZ
Third approach (init block):
open class Club(name: String, country: String) {
var name: String = "Blue"
var country: String = "Australia"
init {
this.name = name
this.country = country
}
}
class FemaleClub(): Club("Green", "NZ") { }
fun main() {
var femaleClub = FemaleClub()
println("RESULT: ${femaleClub.country}")
}
// RESULT: NZ
Fourth approach (class sec.constructor):
open class Club {
var name: String
var country: String
constructor(name: String = "Blue", country: String = "Australia") {
this.name = name
this.country = country
}
}
class FemaleClub(): Club() { }
fun main() {
var femaleClub = FemaleClub()
println("RESULT: ${femaleClub.country}")
}
// RESULT: Australia
In FemaleClub you are not specifying what should be passed to Club as its 2 String arguments, name and country.
And you are not specifying anywhere that FemaleClub takes 2 strings as constructor arguments, so the last line wont work either.
You need to invoke the constructor (primary/secondary) from the class you want to inherit from.
Club only has one constructor, the primary constructor. It takes two strings as parameters. Club does not have an empty constructor.
So, it cannot be invoked as Club().
I would propose two changes.
1) Make name and country of Club properties
open class Club(name: String, country: String)
2) Declare parameters in FemaleClub's primary constructor
Since you want to be able to specify values for name and country when you instantiate FemaleClub it would be a good idea to give the primary constructor of FemaleClub name and country as parameters.
Additionally I would recommend using named parameters when passing on the values, since you can easily mix up the two strings (resulting in passing name as country and country as name.
class FemaleClub(name: String, country: String): Club(name = name, country = country)
New to Swift but have some previous knowledge about C# and Java programming. Trying to understand how "Constructors" and parameter types work in Swift when creating and instantiating a class.
My problem is below:
public class MyClass {
private var somethingA : String
private var somethingB : String
private var somethingC : Int
private var complexes:[String:[String:Int]] = [String:[String:Int]]();
init() {
self.somethingA = "";
self.somethingB = "";
self.somethingC = 0;
self.complexes = [somethingA:[somethingB:somethingC]];
}
public func addSomething(somethingAA : String) {
self.somethingA = somethingAA;
}
public func addComplex(somethingAA: String, complex:(somethingBB: String, somethingCC: Int)) {
self.somethingA = somethingAA;
// How do I assign the complex:(somethingBB, somethingCC) parameter to my self variable 'complexes'?
}
}
When I tried doing it like the following, I get the following errors for each line:
self.somethingB = somethingBB; // Use of unresolved identifier 'somethingBB'
self.somethingC = somethingCC; // Use of unresolved identifier 'somethingCC'
self.complexes = [somethingAA:[somethingBB:somethingCC]]; //use of unresolved identifier 'somethingBB' and 'somethingCC'
the function addComplex(somethingAA: String, complex:(somethingBB: String, somethingCC: Int)) takes a tuple of name complex which consist of String and Int. To assign values from tuple to your properties, you need to use tupleName.propertyName kind of pattern, using this your addAddComplex function becomes
public func addComplex(somethingAA: String, complex:(somethingBB: String, somethingCC: Int)) {
somethingA = somethingAA
somethingB = complex.somethingBB
somethingC = complex.somethingCC
//create a dict with somethingB and somethingC values
complexes = [somethingAA: [somethingB: somethingC]]
print(complexes)
}
Now if you call function addComplex like below which will print ["AAA": ["BBB": 10]]
let myClass = MyClass()
myClass.addSomething(somethingAA: "Hellow")
myClass.addComplex(somethingAA: "AAA", complex: (somethingBB: "BBB", somethingCC: 10))
For error inside function addComplex, parameter complex is tuple, which contains two value named somethingBB of type String and somethingCC of typle Int.
So to access value from tuple you have to access it with dot notation.
self.somethingB = complex.somethingBB
self.somethingC = complex.somethingCC
or you can access parameters from tuple using below syntax also :
self.somethingB = complex.0
self.somethingC = complex.1
To assign value to complexes is type of Dictionary of key-value pair. Here key is type of String and value is another Dictionary of [String:Int]. So you have to construct same structure using raw values from function parameters inside function like below.
self.complexes = [somethingAA:[somethingBB:somethingCC]]
Try this code:
public func addComplex(somethingAA: String, complex:(somethingBB: String, somethingCC: Int)) {
self.somethingA = somethingAA;
self.somethingB = complex.somethingBB
self.somethingC = complex.somethingCC
self.complexes = [somethingAA:[somethingBB:somethingCC]]
}
Tuples are one of Swift's less visible language features. They occupy a small space between Structs and Arrays. In addition, there's no comparable construct in Objective-C (or many other languages).
A tuple can combine different types into one. Tuples are value types
and even though they look like sequences they aren't sequences, as
there's no direct way of looping over the contents.
There are different types of tuples:
// A simple tuple
let tuple1 = (2, 3)
let tuple2 = ("a", "b", "c")
// A named tuple
let tuple3 = (x: 5, y: 3)
// Different types of contents
let tuple4 = (name: "Carl", age: 78, friends: ["Bonny", "Houdon", "Miki"])
The ways in which you can access tuple elements are:
// Accessing tuple elements
let tuple5 = (13, 21)
tuple5.0 // 13
tuple5.1 // 21
let tuple6 = (x: 21, y: 33)
tuple6.x // 21
tuple6.y // 33
Now coming to your question the comlpex parameter is a named tuple In which
complex:(somethingBB: String, somethingCC: Int)
the first parameter in the tuple is somethingBB type of string and somethingCC type of Int.
You can simply access somethingBB and somethingCC by doing
self.somethingB = complex.somethingBB
self.somethingC = complex.somethingCC
or
self.somethingB = complex.0
self.somethingC = complex.1
It is unclear how you want to add the tuple to the complexes property. Do you want to add a new entry in the dictionary? Do you want to replace the existing dictionary with the parameter values?
You probably have a misunderstanding of how tuples work. This parameter:
complex:(somethingBB: String, somethingCC: Int)
Is a parameter called complex, with the type of (somethingBB: String, somethingCC: Int). There is not a single parameter called somethingBB or somethingCC. There is, however, complex.somethingBB and complex.somethingCC. Think of tuples in Swift like System.Tuple in C#, but better. That way, you wouldn't mistake somethingBB and somethingCC as parameters when they are just members of a tuple type.
Now, you should know how to add the tuple into the dictionary. If you want a new entry:
complexes[somethingAA] = [complex.somethingBB: complex.somethingCC]
If you want to replace the existing entry:
complexes = [somethingAA : [complex.somethingBB : complex.somethingCC]]
In production code, you should probably not use complex types like [String: [String: Int]], create a struct or class for it.
EDIT:
If you want to append an entry to the inner dictionary, you need to check whether there is a value associated with the key somethingAA first:
if complexes[somethingAA] == nil {
complexes[somethingAA] = [somethingBB: somethingCC]
} else {
complexes[somethingAA][somethingBB] = somethingCC
}
I have enum with cities that looks like
enum Cities: String {
case la = "Los Angeles"
case ta = "Tel Aviv"
case ny = "New York"
}
And I need to pass sting with city name to one of functions that is waiting for NSString
so this code is not working and I don't understand why
let selectedCity = Cities.ny
myFunc(city : selectedCity)
I get error "Cannot convert value of type 'Cities' to expected argument type 'String!'"
Xcode is suggesting me to use Cities.ny.rawValue as selectedCity.
Swift is strongly typed
So when you pass a value to a function argument the compiler checks that it is of the correct type.
Example
Let's declare a function that receive an Int as parameter
func giveMeYourAge(n: Int) {
}
And now let's try to invoke that function passing something that is NOT an Int
giveMeYourAge(n: "Hello World")
Now the compiler gets angry with us ☠️
error: cannot convert value of type 'String' to expected argument type 'Int'
giveMeYourAge(n: "Hello World")
And it is right (of course). Infact it is telling us that we cannot pass a String to a function that expects an Intindeed.
Your code
When you declare you enum (let's call it City as properly suggested by #Honey) you create a new type City.
enum City: String {
case la = "Los Angeles"
case ta = "Tel Aviv"
case ny = "New York"
}
City is something TOTALLY DIFFERENT from a String.
And we cannot use City in place of a String or viceversa. (Just like in the previous example Int was totally different from String).
So if you have a function that expects a String as parameter
func myFunc(city : String) {
// ...
}
of course you won't be able to pass an value of type City to it.
Wait! What about Polymorphism?
Now let's look at this code
class Animal { }
class Dog: Animal { }
func feed(animal: Animal) {
}
let dog = Dog()
feed(animal: dog)
Why does this code compile??? 😨
This is called polymorphism. When we write
class Dog: Animal { }
we define a new type (Dog) that is more specific than Animal.
Polymorphism does allow us to pass to a function that expects an Animal as param, something that is more specific (like a Dog).
However polymorphism has nothing to do with your example. Even if the syntax is similar.
When you define an enum using this syntax
enum City: String { ... }
You are NOT defining a subtype of String.
You are NOT creating something more specific than a String.
You are NOT using polymorphism.
Instead you are simply creating a new type City that has an instance property (rawValue) of type String.
You need to specify raw value to use the string literal, because without that you are just referring to the enum itself.
let selectedCity = Cities.ny.rawValue
I have better solution, which is much more reasonable... therefore you do this:
enum Cities {
case la
case ta
case ny
var cityString: String{
switch self{
case la:
return "Los Angeles"
case ta:
return "Tel Aviv"
case ny:
return "New York"
}
}
}
Now you need to call just this:
let selectedCity = Cities.ny.cityString
the reason behind me voting over other ideas is that rawValues should be used for recognizing the case, not for getting the values of them... But that's just my opinion :)
It's like you're trying to access a class instance, rather that the property of the instance. It won't work. Specifically what you're trying here is accessing the enum itself which is incorrect. You should access its rawValue property.
From Apple:
You access the raw value of an enumeration case with its rawValue
property:
enum Planet: Int {
case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
}
let earthsOrder = Planet.earth.rawValue
// earthsOrder is 3
if we insert line "case let dictionary as [String : AnyObject]:" inside struct's method everything works fine. But if use inside nested enums we get error "Used undefined type String"
public struct JSON {
public enum Type : Int {
case Number
case String
case Bool
case Array
case Dictionary
case Null
case Unknown
public static func evaluate(object: AnyObject) -> Type {
switch object {
case let dictionary as [String : AnyObject]: // this lines supply error. Use of undefined type String
return .Dictionary
default:
return .Unknown
}
}
} // enum Type
Could some one explain why I have the error with String type?
It seems enum Type contains case String, and it hides the String what you want. I tried the code in Playground and there is no more error after change String to another name.
EDIT
How about reading the project SwiftyJSON (only single file)
https://github.com/SwiftyJSON/SwiftyJSON/blob/master/Source/SwiftyJSON.swift
I does very similar job.(JSON Handling)
It also contains the code looks like this:
public enum Type :Int {
case Number
case String
case Bool
case Array
case Dictionary
case Null
case Unknown
}
I think this project will be very helpful for you.
(and I guess you may end up using this project)
As already said in the other answer, String inside enum Type
refers to the enumeration value. The same problem would occur with
let a : Array<Int> = []
let b : Bool = false
inside methods of enum Type. Renaming the enumeration values is probably the best solution.
But for the sake of completeness: You can solve the problem
by prepending the "Swift" module name explicitly to refer to the
String type:
case let dictionary as [Swift.String : AnyObject]:
If you want to fix this without renaming the enum case, you can change the argument type to Swift.String, i.e.:
case let dictionary as [Swift.String : AnyObject]:
That should work (I had a similar problem and this solved it).