Using switch to assign an instance variable - swift

I'd be grateful for any help - been racking my brains for days and I can't see why this isn't working.
Essentially, I have a main view controller which will be controlled by different classes depending on which game the user selects
'classic'
'unlimited'
'timed'
When the user button is pushed, it needs to flick through the options and assign an instance of the class to a variable 'brain'.
this is what I have:
var brain = GuessMeComparer()
func switcher (random:String) {
switch random {
case "Classic": self.brain = ClassicBrain()
case "unlimited": self.brain = GuessMeComparer()
case "timed": self.brain = TimedBrain()
default:break
}
}
I get the error 'cannot assign a value of type 'ClassicBrain' to a value of type 'GuessMeComparer'.
All I can think of is that you cannot assign instance variables using switch?
Any help would be great, cheers!

Using AnyObject will work but – as vadian is saying – will force you to cast to a specific type later. A better option will be abstract a common interface for all the brain classes in a swift protocol, e.g.:
protocol BrainProtocol {
// common interface here
...
}
class /* or struct */ ClassicBrain : BrainProtocol {
// classic implementation here
...
}
class /* or struct */ TimedBrain : BrainProtocol {
// timed implementation here
...
}
...
var brain : BrainProtocol

Swift is a strong type language, the variable brain is declared as type GuessMeComparer.
Once declared you cannot change the type.
To consider different types, declare the variable explicitly as generic type AnyObject.
var brain : AnyObject = GuessMeComparer()
Now you can assign different types to the variable, but in many cases you have to cast the variable to a specific type later in the code.

Related

Swift constants: Struct or Enum

I'm not sure which of both are better to define constants. A struct or a enum. A struct will be copied every time i use it or not? When i think about a struct with static let constants it makes no sense that it will copied all the time, in my opinion. But if it won't copied then it doesn't matter what I take?
What advantages does the choice of a struct or enum?
Francescu says use structs.
Ray Wenderlich says use enums. But I lack the justification.
Both structs and enumerations work. As an example, both
struct PhysicalConstants {
static let speedOfLight = 299_792_458
// ...
}
and
enum PhysicalConstants {
static let speedOfLight = 299_792_458
// ...
}
work and define a static property PhysicalConstants.speedOfLight.
Re: A struct will be copied every time i use it or not?
Both struct and enum are value types so that would apply to enumerations as well. But that is irrelevant here
because you don't have to create a value at all:
Static properties (also called type properties) are properties of the type itself, not of an instance of that type.
Re: What advantages has the choice of a struct or enum?
As mentioned in the linked-to article:
The advantage of using a case-less enumeration is that it can't accidentally be instantiated and works as a pure namespace.
So for a structure,
let foo = PhysicalConstants()
creates a (useless) value of type PhysicalConstants, but
for a case-less enumeration it fails to compile:
let foo = PhysicalConstants()
// error: 'PhysicalConstants' cannot be constructed because it has no accessible initializers
Here's a short answer: Do your constants need to be unique? Then use an enum, which enforces this.
Want to use several different constants to contain the same value (often useful for clarity)? Then use a struct, which allows this.
One difference between the two is that structs can be instantiated where as enums cannot. So in most scenarios where you just need to use constants, it's probably best to use enums to avoid confusion.
For example:
struct Constants {
static let someValue = "someValue"
}
let _ = Constants()
The above code would still be valid.
If we use an enum:
enum Constants {
static let someValue = "someValue"
}
let _ = Constants() // error
The above code will be invalid and therefor avoid confusion.
Using Xcode 7.3.1 and Swift 2.2
While I agree with Martin R, and the Ray Wenderlich style guide makes a good point that enums are better in almost all use cases due to it being a pure namespace, there is one place where using a struct trumps enums.
Switch statements
Let's start with the struct version:
struct StaticVars {
static let someString = "someString"
}
switch "someString" {
case StaticVars.someString: print("Matched StaticVars.someString")
default: print("Didn't match StaticVars.someString")
}
Using a struct, this will match and print out Matched StaticVars.someString.
Now lets consider the caseless enum version (by only changing the keyword struct to enum):
enum StaticVars {
static let someString = "someString"
}
switch "someString" {
case StaticVars.someString: print("Matched StaticVars.someString")
default: print("Didn't match StaticVars.someString")
}
You'll notice that you get a compile time error in the switch statement on the case StaticVars.someString: line. The error is Enum case 'someString' not found in type 'String'.
There's a pseudo-workaround by converting the static property to a closure that returns the type instead.
So you would change it like this:
enum StaticVars {
static let someString = { return "someString" }
}
switch "someString" {
case StaticVars.someString(): print("Matched StaticVars.someString")
default: print("Didn't match StaticVars.someString")
}
Note the need for parentheses in the case statement because it's now a function.
The downside is that now that we've made it a function, it gets executed every time it's invoked. So if it's just a simple primitive type like String or Int, this isn't so bad. It's essentially a computed property. If it's a constant that needs to be computed and you only want to compute it once, consider computing it into a different property and returning that already computed value in the closure.
You could also override the default initializer with a private one, and then you'll get the same kind of compile time error goodness as with the caseless enum.
struct StaticVars {
static let someString = "someString"
private init() {}
}
But with this, you'd want to put the declaration of the struct in its own file, because if you declared it in the same file as, say, a View Controller class, that class's file would still be able to accidentally instantiate a useless instance of StaticVars, but outside the class's file it would work as intended. But it's your call.
In the Combine framework, Apple has chosen to prefer enums for namespaces.
enum Publishers
A namespace for types that serve as publishers.
enum Subscribers
A namespace for types that serve as subscribers.
enum Subscriptions
A namespace for symbols related to subscriptions.

Is there any way to get the list of attributes of a class without any instantiated object?

I already know that we can get the list of attributes of a object using reflection in Swift, but all the examples that I found and have implemented so far uses a instantiate object. Something like that:
func attributeList() -> [String] {
var attributeList = [String]()
let serializableMirror = Mirror(reflecting: self) //using instantiate object
for childMirror in serializableMirror.children {
if let label = childMirror.label {
attributeList.append(label)
}
}
return attributeList
}
My question is, there is any way to get the attributes of a class without any reference to it? Some kind of static method where I pass my desired class type and get the attributes list of it.
In all implementations of reflection that I've worked with you need an object for the reflection to work on.
Whether it's one you provide or one the system creates for you, you have to have a concrete object.

Return different Types with getter method on a variable in Swift 2

I've making a Hangman game which has two modes: normal and evul. Normal and evul are both subclasses of mode. The class mode saves up things like: good guessed letters, wrong guessed letters and mode has a guess function.
class Mode
Normal: Mode
Evul: Mode
Now I wanna make my code as simple as possible, so I thought that before start the game and when the view get's loaded I will initiate either the evul subclass or the normal subclass. I got a local variable called which returns return or false based on the fact if evulmode is enabled or not. So when it's not the getter function will initiate the normal subclass. So like this I dont need any if statements anymore and makes my gamecode alot simpler.
Problem: since the normal subclass is of another type than evul subclass it wont work. This is the error I get:cannot convert returntype x to type x.
This is the code I have:
var Game: Normal {
get {
if evulMode == false {
return(Normal())
} else {
return(Evul())
}
}
}
A Solution or any f
Feedback on how to do it better is appriciated.
I would make Mode rawRepresentable and then create an enum to represent all game mode options. Then you can create a variable with the enum as type.
To make your code work, give the variable the superclass type. Then use a downcast.
class Mode {
}
class Normal : Mode {
let someAttr : Int = 10
}
class Evul : Mode {
let someOtherAttr : String = "ABC"
}
var evulMode : Bool = false
var game: Mode {
get {
if evulMode == false {
return(Normal())
} else {
return(Evul())
}
}
}
After downcasting you will have access to all properties and methods specific to the subclass.
if let normalGame = game as? Normal {
print(normalGame.someAttr)
}
if let evulGame = game as? Evul {
print(evulGame.someOtherAttr)
}
Mode can also be a protocol. You just need something both Normal and Evul conform too or inherit from. Protocols have the advantage that you can conform to multiple protocols while you can only inherit from one superclass.
protocol Mode {
}

Difference between type method and type instance method, etc?

Note: I've read the apple documentation and studied a swift book.
I'm confused on the difference between a "type instance method" (if such exists, correct me if I'm wrong) and a type method?
Difference between class method and instance method?
Difference between type property and instance property(if such exists, sorry I'm very confused on Type Properties subject)?
Lastly, Do class properties exist in swift?
Sorry for the confusion :'(
In Swift, types are either named types or compound types. Named types include classes, structures, enumerations, and protocols. In addition to user-defined named types, Swift defines many named types such as arrays, dictionaries, and optional values. (Let's ignore compound types for now since it doesn't directly pertain to your question.)
To answer your questions, suppose that I create a user defined class called Circle (this is just an example):
class Circle {
static let PI = 3.14
var radius: Double
init(radius: Double) {
self.radius = radius
}
// Returns the area of this circle
func area() {
return PI * radius
}
// Ridiculous class method for demonstration purposes
static func printTypeName() {
println("Circle")
}
}
I'm confused on the difference between a "type instance method"
(if such exists, correct me if I'm wrong) and a type method?
As mentioned earlier, a type refers to a class, structure, enumeration, protocol, and compound types. In my example above, I use a class called Circle to define a type.
If I want to construct an individual object of the Circle class then I would be creating an instance. For example:
let myCircleInstance = Circle(radius: 4.5)
let anotherCircleInstance = Circle(radius: 23.1)
The above are objects or instances of Circle. Now I can call instance methods on them directly. The instance method defined in my class is area.
let areaOfMyCircleInstance = myCircleInstance.area()
Now, a type method is a method that can be called directly on the type without creating an instance of that type.
For example:
Circle.printTypeName()
Notice that there is a static qualifier before the func. This indicates that it pertains to the type directly and not to an instance of the type.
Difference between class method and instance method?
See the explanation above.
Difference between type property and instance property(if such
exists, sorry I'm very confused on Type Properties subject)?
This is a similar explanation to the one in your question one except that instead of applying to methods, it applies to the properties (i.e., attributes, variables) of the type.
In my Circle example, the properties are defined as:
static let PI = 3.14
var radius: Double
The property PI is a type property; it may be accessed directly by the type
Circle.PI
The property radius is an instance property of the type; it may be accessed by an instance of the type. Using the variables we created earlier:
// I can do this; it will be 4.5
myCircleInstance.radius
// And this; it will be 23.1
anotherCircleInstance.radius
// But I CANNOT do this because radius is an instance property!
Circle.radius
Lastly, Do class properties exist in swift?
Absolutely! Read my explanation to your question 3 above. The PI property in my example is an example of a class property.
References:
Swift Language Reference - Types
Swift Language Reference - Properties
Swift Language Reference - Methods
The difference is that instance methods and properties are created for every instance. Type methods and properties are created for the whole type
Let's say you have struct Employee
struct Employee {
static var ID:Int = 0
static var NAME:Int = 1
static func getNameOfField(index:Int) -> String {
var fieldName:String = ""
if index == ID {
fieldName = "Id"
} else if index == NAME {
fieldName = "Name"
}
return fieldName
}
var fields = [Int:String]()
mutating func config(id:String, name:String) {
fields[Employee.ID] = id
fields[Employee.NAME] = name
}
func getField(index:Int) -> String {
return fields[index]!
}
}
var e0 = Employee()
e0.config("1", name: "Mark")
var e1 = Employee()
e1.config("2", name: "John")
print(e0.getField(Employee.NAME)) // prints "Mark"
print(Employee.getNameOfField(Employee.ID)) // prints "Id"
Each instance of the struct e0 and e1 has property fields. It is created for every instance and lives in it. The values stored in the fields property are different for every instance. That's why it is called "instance property"
Each instance also has method getField. It is created for every instance and it has access to its properties and methods in that case to the instance's var fields. That's why it is called "instance method"
You access instance properties and methods by referencing the instance (in our case e0 and e1)
ID and NAME are type properties or static properties. The are created only once and have the same value for every instance and for every other object.
You access type properties by referencing the "type" (in our case the struct) Employee.NAME
Type methods are something like a global function for a type(struct, class, enum). They are usually used to encapsulate functionality that is bound to the type but may not require an instance. Like in the example the type method getNameOfField(index:Int) -> String returns the field's name based on an index. To return this information you don't have to create na instance of Employee
Types are structs, classes and enums
You define type methods and properties with the keyword static (that's why they are also called static methods and properties)
Structs and enums can have type properties and type methods.
Classes can only have type methods. You can create type property but it has to be computational
In classes you can define type methods with static or class keyword. The difference is that class methods can be overridden.
whyceewhite - thank you so much! You have clarified something that I could just not grasp!
For those of you who come to this page and are operating on Swift 3+, please see the code below if you want to put the code into practice and see static in operation.
class Circle {
static let PI = 3.14
var radius: Double
init(radius: Double) {
self.radius = radius
}
// Returns the area of this circle
func area() -> Double {
return Double.pi * radius
}
// Ridiculous class method for demonstration purposes
static func printTypeName() {
print("Circle")
}
}
Then start trying Circle.printTypeName or the examples shown above! Great stuff!
It is all about scopes, it defines a boundary of where and how you can use a function. A method can only be used after you initialized an object from the class. Simply to say, in order to use the method, you have to created the object first, method belongs to the object.
But, what if you need to use a method but do not need to initiate an object, say, a global setting (ex. authorizationStatus() function in CLLocationManager for GPS coordinates authorization), you can then create a type method and simply by refer to the type name (NOT object name) and followed by the classic doc function calling.
#PaulBart1 fix of #whyceewhite example is a little tricky, because he replace declarated PI for pi that is constant known default by swift.
I rewrote this example for Swift 4 like this:
class Circle {
//static let PI = 3.14 -> error: static member 'PI' cannot be used on instance of type 'Circle'
let PI: Double = 3.1415
var radius: Double
init (radius: Double) {
self.radius = radius
}
// Return the area of this Circle
func area() -> Double {
return PI * radius
}
// Radius class method for demonstration purposes
static func printTypeName() {
print("Circle")
}
}
let myCircleInstance = Circle(radius: 4.5)
let anotherCircleInstance = Circle(radius: 23.1)
Circle.printTypeName() // Circle
print(myCircleInstance.area()) // 14.13675
print(anotherCircleInstance.area()) // 72.56865
//

Duplicating declarations in a swift playgground

is there a way to introduce the concept of 'scope' while trying things out in playground?
Say you want to test a couple of implementations of a class MyClass so you declare it, write some code to test things. You then decide you want to compare that with another version of class MyClass implementation.
Redeclaring MyClass will give a redeclaration error.
So can I have playground treat the first declaration of MyClass and associated code separately from the second without changing the class name or creating multiple playgrounds?
thanks
It's a bit of a hack, but you can use nested types for this – declare a struct the only purpose of which is to have this kind of scoping:
struct Scope1 {
class MyClass { }
}
struct Scope2 {
class MyClass { }
}
let x = Scope1.MyClass()
let y = Scope2.MyClass()
// if you want to quickly switch between using
// one vs the other
typealias MyClass = Scope1.MyClass
let z = MyClass()
No, there isn't. Playground files are order-dependent and run in top-down lexical order.