Protocols and composition on Swift - swift

I am trying to learn more about protocols and got stuck without understanding what is going on on the following piece of code. Mostly seeking some light and direction for good articles and pieces of explanation basically.
In one of the examples from Apple's Library protocols are doing a bit more than making sure the classes conform to it.
They are allowing objects from one class to access methods within other classes without using the traditional class inheritance definition.
This line of code let generator: RandomNumberGenerator on the Dice class is allowing the var d6 that is of type Dice to access a function func random() -> Double that is outside of Dice scope and inside LinearCongruentialGenerator scope and is using the RandomNumberGenerator to make this bridge.
Also allowing to do the following call d6.generator.random() when again .ramdom() is not on Dices scope.
protocol RandomNumberGenerator {
func random() -> Double
}
class LinearCongruentialGenerator: RandomNumberGenerator {
var lastRandom = 42.0
let m = 139968.0
let a = 3877.0
let c = 29573.0
func random() -> Double {
lastRandom = ((lastRandom * a + c) % m)
return lastRandom/m
}
}
class Dice {
let sides: Int
let generator: RandomNumberGenerator
init(sides: Int, generator: RandomNumberGenerator) {
println(generator.random())
self.sides = sides
self.generator = generator
}
func roll() -> Int {
return Int(generator.random() * Double(sides)) + 1
}
}
var d6 = Dice(sides: 6, generator: LinearCongruentialGenerator())
Update to question
Thanks for the answers! By doing some research I think I just touched composition. So I wrote the code bellow to exemplify composition a bit better, without using protocols or delegates. Just pure composition. Please let me know if I got it right as it may help other people trying to understand composition.
class A {
var a1: String
init (valueToA: String){
self.a1 = valueToA
}
func aFunc1() -> A {
return self
}
}
class B {
var b1: A
init (valueToB: A ) {
self.b1 = valueToB
}
func bFunc1(){
println("I am bFunc and I am calling aFunc \(b1.aFunc1())")
}
}
var myA = A(valueToA: "Initiated myA with this string")
//myA.aFunc1()
var myB = B(valueToB: myA)
myB.b1 = A(valueToA: "a value to B")
myB.b1.aFunc1()
The same code but now with protocols
protocol myProtocol {
func protocolFunc(value: String) -> String
}
class A: myProtocol {
var a1: String
init (valueToA: String){
self.a1 = valueToA
}
func aFunc1() -> A {
return self
}
func protocolFunc(value: String) -> String {
return value
}
}
class B {
var b1: A
var b2: myProtocol
init (valueToB1: A, valueToB2: myProtocol ) {
self.b1 = valueToB1
self.b2 = valueToB2
}
func bFunc1(){
println("I am bFunc and I am calling aFunc \(b1.aFunc1())")
}
func callProtocolFuncOnA (value: String) {
b1.protocolFunc(value)
}
}
var myA1 = A(valueToA: "my A 1 created")
var myA2 = A(valueToA: "my A 2 created")
var myB = B(valueToB1: myA1, valueToB2: A(valueToA: "my A 3 created"))
myB.callProtocolFuncOnA("calling other function")

As #DevAndArtist says in his comment it allows encapsulation (abstraction) when a type of RandomNumberGenerator is passed in the initializer of the Dice class and so only that part of your implementation is visible to you.
In my humble opinion it could be better if the constant generator was not visible outside the Dice class scope as you say in your question, for example making his access modifier private, but remember that in your example all is set in the same swift file and this implies that the private access modifier isn't like the other programming languages like C#, Java, etc.
Even doing private you can access d6.generator.random() in your call because it exist in the same Swift file, the only way you can hide the property if you create a new Swift file for the Dice class and then this call when the property is private of course :
var d6 = Dice(sides: 6, generator: LinearCongruentialGenerator())
println(d6.generator.random())
gave you the following error:
'Dice' does not have a member named 'generator'
And you can hide the property outside of its scope. It's only a point of view.
I hope this help you.

Related

Swift Error Code: Instance member 'getStory' cannot be used on type 'StoryBrain'; did you mean to use a value of this type instead?

Can't figure out how to go about this swift error code... Do I need to make an instance or make it static??
struct Story{
var storyTitle : String
var choice1 : String
var choice2 : String
init(t: String,c1: String, c2: String ) {
storyTitle = t
choice1 = c1
choice2 = c2
} }
struct StoryBrain{
var storyNumber = 0
let stories = [
Story(t: "You see a fork in the road", c1: "Take a left", c2: "Take a right"),
Story(t: "You see a tiger", c1: "Shout for help", c2: "Play dead"),
Story(t: "You find a treasure chest", c1: "Open it", c2: "Check for traps")
]
func getStory() -> String{
return stories[storyNumber].storyTitle
}
mutating func nextStory(userChoice: String) {
if storyNumber + 1 < stories.count{
storyNumber += 1
} else {
storyNumber = 0
}
}
}
func updateUI(){
storyLabel.text = StoryBrain.getStory()}
I guess your doing Angelas "iOS & Swift - The Complete iOS App Development Bootcamp" course on Udemy.
Inside the ViewController, create a var:
class ViewController: UIViewController {
var storyBrain = StoryBrain()
#IBOutlet weak var storyLabel: UILabel! }
This allows you to tap into your StoryBrain Model. Good luck!
The issue is here:
StoryBrain.getStory()
^ Instance member 'getStory' cannot be used on type 'StoryBrain'
As the error indicates, getStory is an instance method, meaning that you can only call it on instances of StoryBrain. Here are a couple other suggestions:
struct StoryBrain {
// Make private by default
private let stories = [...]
private var storyNumber = 0
// Make a computed property
var currentStoryTitle: String {
stories[storyNumber].storyTitle
}
// Make the name imperative; reflects that this is a mutating function
// Also don't need mutating anymore since this is a class
func advanceStory(...) {
...
}
}
If you initialize this object, like let brain = StoryBrain(), then you can use instance members like advanceStory and currentStoryTitle on brain. You’ll want to create this object/store it in whatever class you have updateUI in. If you use the same brain from a couple different places, then you might want to use the singleton pattern, which you can see in the original edit to this answer.

Make a Functions Able to Handle Different Classes as Parameters

I'm trying to pass different classes, with the same properties, to the same function. How do I cast them for use with this function?
Below is a simple example to highlight what I'm trying to achieve.
class A {
var height:Int = 10
}
class B {
var height:Int = 20
}
class C {
static func grow(class:AnyObject) {
class.height + 5
}
}
C.grow(A)
C.grow(B)
The two final calls should yield 15 and 25, but without casting the AnyObject back to A or B, an error like the following is generated: "AnyObject has no member named".
How do I accomplish something like this?
Swift reflection API enables you to read values but not modify them. So if that's enough for you, you may use a method similar to the following which takes an object and the label of the member you want to access:
func getValue<T>(object: AnyObject, memberLabel: String) -> T? {
let mirror = Mirror(reflecting: object)
for member in mirror.children {
if let _ = member.label where member.label == memberLabel,
let value = member.value as? T {
return value
}
}
return nil
}
But if you want to modify the values, you have to define a protocol and make the classes conform to it:
protocol HasHeight {
var height: Int { get set }
}
extension HasHeight {
mutating func grow() {
self.height += 5
}
}
class A : HasHeight {
var height = 10
}
class B : HasHeight {
var height = 20
}
var a = A()
print(a.height)
a.grow()
print(a.height)
var b = B()
print(b.height)
b.grow()
print(b.height)
Here I defined grow() as a protocol extension so that it is available on every class/struct that conforms to the HasHeight protocol.
The results are:
10
15
20
25
You may define it elsewhere, but the call will have to be changed to include an & reference:
func grow<T: HasHeight>(inout sized: T) {
sized.height += 5
}
grow(&b)
Looks like a good case for a protocol! Define one with a height property, have A and B both implement that protocol, and then have the grow method accept the protocol as its parameter.

Using a Type Variable in a Generic

I have this question except for Swift. How do I use a Type variable in a generic?
I tried this:
func intType() -> Int.Type {
return Int.self
}
func test() {
var t = self.intType()
var arr = Array<t>() // Error: "'t' is not a type". Uh... yeah, it is.
}
This didn't work either:
var arr = Array<t.Type>() // Error: "'t' is not a type"
var arr = Array<t.self>() // Swift doesn't seem to even understand this syntax at all.
Is there a way to do this? I get the feeling that Swift just doesn't support it and is giving me somewhat ambiguous error messages.
Edit: Here's a more complex example where the problem can't be circumvented using a generic function header. Of course it doesn't make sense, but I have a sensible use for this kind of functionality somewhere in my code and would rather post a clean example instead of my actual code:
func someTypes() -> [Any.Type] {
var ret = [Any.Type]()
for (var i = 0; i<rand()%10; i++) {
if (rand()%2 == 0){ ret.append(Int.self) }
else {ret.append(String.self) }
}
return ret
}
func test() {
var ts = self.someTypes()
for t in ts {
var arr = Array<t>()
}
}
Swift's static typing means the type of a variable must be known at compile time.
In the context of a generic function func foo<T>() { ... }, T looks like a variable, but its type is actually known at compile time based on where the function is called from. The behavior of Array<T>() depends on T, but this information is known at compile time.
When using protocols, Swift employs dynamic dispatch, so you can write Array<MyProtocol>(), and the array simply stores references to things which implement MyProtocol — so when you get something out of the array, you have access to all functions/variables/typealiases required by MyProtocol.
But if t is actually a variable of kind Any.Type, Array<t>() is meaningless since its type is actually not known at compile time. (Since Array is a generic struct, the compiler needs know which type to use as the generic parameter, but this is not possible.)
I would recommend watching some videos from WWDC this year:
Protocol-Oriented Programming in Swift
Building Better Apps with Value Types in Swift
I found this slide particularly helpful for understanding protocols and dynamic dispatch:
There is a way and it's called generics. You could do something like that.
class func foo() {
test(Int.self)
}
class func test<T>(t: T.Type) {
var arr = Array<T>()
}
You will need to hint the compiler at the type you want to specialize the function with, one way or another. Another way is with return param (discarded in that case):
class func foo() {
let _:Int = test()
}
class func test<T>() -> T {
var arr = Array<T>()
}
And using generics on a class (or struct) you don't need the extra param:
class Whatever<T> {
var array = [T]() // another way to init the array.
}
let we = Whatever<Int>()
jtbandes' answer - that you can't use your current approach because Swift is statically typed - is correct.
However, if you're willing to create a whitelist of allowable types in your array, for example in an enum, you can dynamically initialize different types at runtime.
First, create an enum of allowable types:
enum Types {
case Int
case String
}
Create an Example class. Implement your someTypes() function to use these enum values. (You could easily transform a JSON array of strings into an array of this enum.)
class Example {
func someTypes() -> [Types] {
var ret = [Types]()
for _ in 1...rand()%10 {
if (rand()%2 == 0){ ret.append(.Int) }
else {ret.append(.String) }
}
return ret
}
Now implement your test function, using switch to scope arr for each allowable type:
func test() {
let types = self.someTypes()
for type in types {
switch type {
case .Int:
var arr = [Int]()
arr += [4]
case .String:
var arr = [String]()
arr += ["hi"]
}
}
}
}
As you may know, you could alternatively declare arr as [Any] to mix types (the "heterogenous" case in jtbandes' answer):
var arr = [Any]()
for type in types {
switch type {
case .Int:
arr += [4]
case .String:
arr += ["hi"]
}
}
print(arr)
I would break it down with the things you already learned from the first answer. I took the liberty to refactor some code. Here it is:
func someTypes<T>(t: T.Type) -> [Any.Type] {
var ret = [Any.Type]()
for _ in 0..<rand()%10 {
if (rand()%2 == 0){ ret.append(T.self) }
else {
ret.append(String.self)
}
}
return ret
}
func makeArray<T>(t: T) -> [T] {
return [T]()
}
func test() {
let ts = someTypes(Int.self)
for t in ts {
print(t)
}
}
This is somewhat working but I believe the way of doing this is very unorthodox. Could you use reflection (mirroring) instead?
Its possible so long as you can provide "a hint" to the compiler about the type of... T. So in the example below one must use : String?.
func cast<T>(_ value: Any) -> T? {
return value as? T
}
let inputValue: Any = "this is a test"
let casted: String? = cast(inputValue)
print(casted) // Optional("this is a test")
print(type(of: casted)) // Optional<String>
Why Swift doesn't just allow us to let casted = cast<String>(inputValue) I'll never know.
One annoying scenerio is when your func has no return value. Then its not always straightford to provide the necessary "hint". Lets look at this example...
func asyncCast<T>(_ value: Any, completion: (T?) -> Void) {
completion(value as? T)
}
The following client code DOES NOT COMPILE. It gives a "Generic parameter 'T' could not be inferred" error.
let inputValue: Any = "this is a test"
asyncCast(inputValue) { casted in
print(casted)
print(type(of: casted))
}
But you can solve this by providing a "hint" to compiler as follows:
asyncCast(inputValue) { (casted: String?) in
print(casted) // Optional("this is a test")
print(type(of: casted)) // Optional<String>
}

Cyclic loop between protocols in swift

I'm trying to define some protocols in a Swift file, however I've noticed that if the protocols have crossed references XCode becomes buggy and it's impossible to work with the project. The example of used protocols might be the one used below:
protocol VIPERPresenterProtocol
{
var view: VIPERViewProtocol? { get set }
var interactor: VIPERInteractorInputProtocol? { get set }
var wireFrame: VIPERWireFrame? { get set }
// /* Add your extra communication methods here */
// /* Presenter -> ViewController */
}
protocol VIPERViewProtocol
{
var presenter: VIPERPresenterProtocol? { get set }
}
Where the VIPERPresenterProtocol has a reference to the VIPERViewProtocol and this last has a reference to the VIPERPresenterProtocol.
This is something that works in Objective-C but that Swift doesn't like. My question is, is this something Apple doesn't expect to support in Swift, if it might be a bug of the Swift language or if I should implement this in any other way.
Your question has a form of:
protocol A
{
var b: B? { get set }
}
protocol B
{
var a: A? { get set }
}
However, while the two protocol declarations compile, any attempt to implement them as such does not:
protocol A {
var b: B? { get set }
}
protocol B {
var a: A? { get set }
}
// on their own, the two protocol declerations compile
class Ca: A { // Does not compile: --> Segmentation fault 11
var b: B?
}
This does not happen if we break the cycle:
protocol A {}
protocol B {
var a: A? { get set }
}
class Ca: A {}
class Cb: B {
var a: A?
}
let cb = Cb() // --> {nil}
cb.a = Ca() // --> {{Ca}}
cb.a // --> {Ca}
Or if we define the two protocols in terms of concrete types:
protocol A {
var b: Cb? { get set }
}
protocol B {
var a: Ca? { get set }
}
class Ca: A {
var b: Cb?
let i = "A"
}
class Cb: B {
var a: Ca?
let i = "B"
}
let cb = Cb() // --> {nil "B"}
cb.a = Ca() // --> {{{...}} "B"}
cb.a // --> {{nil "A"}}
cb.a!.b = Cb() // --> {{{...} "A"}}
My impression is that the type checker cannot yet deal with recursive type declarations. Whether it ever will, may be an open question even to Apple at this point, though, because of the clear intention to facilitate functional idioms, this must at least be a possibility.
I have answered a similar question before, though, as I eventually realised with the help of #newacct, not identical.
EDIT
I have just upgraded to Xcode 6.1 GM Seed and things have changed! The following snippet now compiles and appears to run fine!
protocol A {
var b: B? { get set }
}
protocol B {
var a: A? { get set }
}
class Ca: A {
var b: B?
}
class Cb: B {
var a: A?
}
let a = Ca() // --> {nil}
let b = Cb() // --> {nil}
a.b = b // --> {{{...}}}
b.a = a // --> {{{...}}}
(This improvement, however, does not extend to recursively defined associated types.)
I was trying to build something similar too for VIPER, and I encountered the same problems.
I add something to the good answer of milos: I succeeded to break the cycle even when using associated types, using a couple of supporting protocols.
protocol _VIPERViewProtocol {
}
protocol VIPERViewProtocol : _VIPERViewProtocol {
typealias P:_VIPERPresenterProtocol
var presenter: P! {get set}
}
protocol _VIPERPresenterProtocol {
}
protocol VIPERPresenterProtocol : _VIPERPresenterProtocol {
typealias W:_VIPERViewProtocol
var view: W! {get set}
}
This has the advantage of letting the compiler infer the right type of the associated presenter and view, for example:
class BasePresenter : VIPERPresenterProtocol {
var view : BaseView!
}
class BaseView : VIPERViewProtocol {
var presenter: BasePresenter!
}
var p = BasePresenter()
// p.view is correctly recognized as BaseView!
This is valid as long as you use an associated type. Since there is no covariance for properties in Swift, the above code would not compile if you change it like this:
protocol VIPERViewProtocol : _VIPERViewProtocol {
var presenter: _VIPERPresenterProtocol! {get set}
}
Anyway, stepping back to the VIPER architecture, this helps only for giving the concrete classes a template that they must implement.
It would be much more useful if we could define a "builder" method that takes the generic objects conforming to the protocols (wireframe, presenter..), and that wires up all the components.
Unfortunately, something like this doesn't work:
func builder(p:VIPERPresenterProtocol, v:VIPERViewProtocol) {
p.view = v
v.presenter = p
}
compiler complains about Protocol 'VIPERViewProtocol' can only be used as a generic constraint because it has Self or associated type requirements.
Maybe one solution to explore is generics, but I still have to think about it.

Assigning to a var defined in Protocol says that it can't assign to it

Here is a simple use case:
protocol Debuggable {
var _d: String -> () {
get set
}
}
class Debugger {
class func attach(instance: Debuggable) {
let d = Debugger()
instance._d = d.d // This doesn't work
}
func d(message: String) {
println(message)
}
}
Error message at compile time: Cannot assign to _d in instance, although my protocol defines the var with a getter and setter.
This is a good case of the compiler catching an error for you :)
instance may be a value type and therefore be copied in to this method. In that case, you will modify the copy and just throw it out. The quickest fix is to define it as an inout parameter:
class func attach(inout instance: Debuggable) {
let d = Debugger()
instance._d = d.d
}
I think it would be better to return the instance though:
class func attach(instance: Debuggable) -> Debuggable {
let d = Debugger()
var ret = instance
ret._d = d.d
return ret
}
I feel that inout is mostly in the language for backwards compatibility to Objective-C and C. Let the type determine if it should be copied instead of forcing it to be passed by reference. If something is defined as a value type, there is a good reason for it.