Swift 2.0 beta: are protocols kinda broken in Xcode beta 5? - xcode

Currently I'm working on my new App written with Swift 2.0. Today I faced two strange errors in Xcode beta 5. I'd love if someone with a previous beta version of Xcode can confirm if I'm right or not. I also could misunderstand something, so I'll appreciate any feedback.
Here is some example code that made me struggle a while:
// Frist bug
protocol SomeProtocol {
var someArray: [String] { get set } // #1 bug
}
extension SomeProtocol {
func someFunction(someString: String) {
self.someArray.append(someString) // #1: Immutable value of type '[String]' only has mutating members named 'append'
}
}
// Second bug
protocol SomeInterfaceProtocol {
var someBool: Bool { get set } // #2 bug
}
class SomeClass: SomeInterfaceProtocol {
var someBool: Bool = false
func returnInterface() -> SomeInterfaceProtocol {
return self
}
}
let someInstance = SomeClass()
// can't set the value
someInstance.returnInterface().someBool = true // #2: Cannot assign to property: function call returns immutable value

The first error can be solved if you add the modifier mutating before the extension func declaration like this:
mutating func someFunction(someString: String) {
I suspect that's a change in the language.
The other one puzzles me as well. At least, here's a work-around:
var c = someInstance.returnInterface()
c.someBool = true

I think the second one isn't a bug as well for the same reason that you can't modify an item in a dictionary directly, or that you can't change elem in for elem in array { ... }.
Something has to be saved to be able to change it. Because you're returning the protocol type, the compiler can't know whether it's a struct or a class, whereas if it's a struct the operation of changing it would have no effect because it's not persisted in any way and structs aren't passed by reference. That's why Thomas' workaround works. Maybe it'll work too if returnInterface returned a class instance, instead of the protocol type.
EDIT: Just tried it out: Indeed it works either if you return SomeClass instead of SomeInterfaceProtocol or if you change the protocol to a class protocol, as it can't be a struct
protocol SomeInterfaceProtocol : class {
var someBool: Bool { get set }
}
class SomeClass: SomeInterfaceProtocol {
var someBool: Bool = false
func returnInterface() -> SomeInterfaceProtocol {
return self
}
}
or
protocol SomeInterfaceProtocol {
var someBool: Bool { get set }
}
class SomeClass: SomeInterfaceProtocol {
var someBool: Bool = false
func returnInterface() -> SomeClass {
return self
}
}
both work

Related

Swift Type Inference Not Working (Xcode 7.1.1)

This is my first question on StackOverflow so please go easy on me.
I've been struggling with getting Swift to invoke the appropriate generic overload.
Suppose I have the following protocol -
protocol MyProtocol { }
And I have the following generic methods -
func foo<T>() -> T
func foo<T: MyProtocol>() -> T
One would expect that invoking foo() with a return type of T conforming to MyProtocol would invoke the appropriate overload.
let bar: MyProtocol = foo()
The above code actually invokes the following function during runtime and Cmd + Click in the IDE navigates to the wrong overload as well.
func foo<T>() -> T
For some reason I cannot get this to work properly in Xcode 7.1.1.
Am I missing something completely fundamental here or is this another Swift quirk?
EDIT
Adding an example of this behavior in action as per matt's request.
protocol MyProtocol { }
class MyProtoClass : MyProtocol { }
class Bar {
func foo<T>(value: T) {
print("T is Generic")
}
func foo(value: MyProtocol) {
print("T conforms to MyProtocol")
}
}
class MyClass<T> {
var value: T
init(value: T) { self.value = value }
var b = Bar()
func print() {
b.foo(value)
}
}
MyClass<MyProtocol>(value: MyProtoClass()).print()
MyClass<String>(value: "").print()
Copying and pasting the above code into a Swift command line application and executing yields the following output.
T is Generic
T is Generic
I think the problem here is that protocols in generics (and generally in Swift) don't work the way you want them to. They are not acting as first-class types. I know that's rather vague... but look at it this way; if you eliminate the func foo<T>(value: T) version of foo, your code won't even compile. In other words, Swift isn't making a choice of foo and choosing wrong; it's saying that b.foo(a1.value) does not call func foo<T: MyProtocol>(value: T).
I have a vague feeling that this is related to my question here:
Protocol doesn't conform to itself?
Okay, I am going to answer my own question here.
After some investigation it seems that Swift wants you to implement an extension with a type constraint on the generic parameter.
extension MyClass where T : MyProtocol {
func print() {
b.foo(value)
}
}
I know this doesn't really solve the problem but it was sufficient enough for me as a work around in my real world use case.
The above sample would wind up looking something like the following.
protocol MyProtocol { }
class MyProtoClass : MyProtocol { }
class Bar {
func foo<T>(value: T) {
print("T is Generic")
}
func foo(value: MyProtocol) {
print("T conforms to MyProtocol")
}
}
class MyClass<T> {
var value: T
init(value: T) { self.value = value }
var b = Bar()
func print() {
b.foo(value)
}
}
extension MyClass where T : MyProtocol {
func print() {
b.foo(value)
}
}
MyClass<MyProtoClass>(value: MyProtoClass()).print()
MyClass<String>(value: "").print()

Type variable in protocol - Swift 2

So I have a protocol, and in it I want a variable that is a class type. That way I can init that class from the variable.
Keep in mind that there will be many different classes. I made a quick example.
I get the error "type 'CashRegister' does not conform to protocol 'RegisterProtocol'"
This example isn't exactly what I'm doing, but it gets the point across. Thanks for the help.
protocol RegisterProtocol {
var currentBill: DollarBillProtocol {get set}
func makeNewBill()->DollarBillProtocol
}
extension RegisterProtocol {
func printCurrentBill() {
Swift.print(currentBill)
}
}
class CashRegister: RegisterProtocol {
var currentBill = OneDollarBill.self
func makeNewBill() -> DollarBillProtocol {
return currentBill.init()
}
}
protocol DollarBillProtocol {
// protocol that all bills have in common
}
class OneDollarBill: DollarBillProtocol {
required init(){
}
}
class FiveDollarBill: DollarBillProtocol {
required init(){
}
}
The way you declare currentBill in CashRegister makes it a var of type class. But the protocol RegisterProtocol requires this variable to be of type DollarBillProtocol in any class that implements the protocol. The compile error is because of this mismatch.
To make this more clear, you could declare the var with the explicit type, as follows:
class CashRegister: RegisterProtocol {
var currentBill: DollarBillProtocol = OneDollarBill() // or other initial value
}

Swift: filter protocol array by comparing types

(first post)
usually im able to find answers here or elsewhere but no luck this time =(
Question: in Swift, how do you filter an array that is of a protocol type by an implementing type supplied as a function parameter?
protocol Aprotocol {
var number:Int { get set }
}
class Aclass: Aprotocol {
var number = 1
}
class AnotherClass: Aprotocol {
var number = 1
}
var array:[Aprotocol] = [ Aclass(), AnotherClass(), Aclass() ]
func foo (parameter:Aprotocol) -> Int {
return array.filter({ /* p in p.self == parameter.self */ }).count
}
var bar:Aprotocol = // Aclass() or AnotherClass()
var result:Int = foo(bar) // should return 2 or 1, depending on bar type
maybe this is not the right approach at all?
thanks!
Here is what I think you want:
return array.filter { (element: Aprotocol) -> Bool in
element.dynamicType == parameter.dynamicType
}.count
But I recommend this, which does the same, but without the useless instance of Aclass() which is passed in the answer on the top. Also this way is faster:
func foo <T: Aprotocol>(type: T.Type) -> Int {
return array.filter { (element: Aprotocol) -> Bool in
element.dynamicType == type
}.count
}
var result:Int = foo(Aclass)
The dynamicType will return the Type of an instance
Very easy:
return array.filter({ parameter.number == $0.number }).count
Kametrixoms solution works (if you use "is T" instead of "== type") but in my case, since i didnt know which implementing class was going to call it, had to go with this solution:
protocol Aprotocol: AnyObject {
var number:Int { get set }
}
class func foo(parameter: AnyObject) -> Int {
return array.filter ({ (element: Aprotocol) -> Bool in
object_getClassName(element) == object_getClassName(parameter)
}).count
}

Swift filter function causes compile error

I have created a wrapper class for storing a weak object reference, and then. I want to remove objects that have not a valid reference inside.
class Weak<T: AnyObject> {
weak var value : T?
init (value: T) {
self.value = value
}
}
protocol CSLocationServicesDelegate : class{
}
class conformance : CSLocationServicesDelegate{
}
class Dispatcher{
var dispatchArray = Array<Weak<CSLocationServicesDelegate>>()
func add( delegate : CSLocationServicesDelegate!){
dispatchArray.append(Weak(value: delegate));
}
func remove(obj : CSLocationServicesDelegate!){
dispatchArray.filter { (weakRef : Weak<CSLocationServicesDelegate>) -> Bool in
return weakRef.value != nil; //change this line to "return true" and it works!!!
}
}
}
However Xcode compilation fails with an error being reported, which shows absolutely no specific error. I suspect that I am using the language in such a false manner, that Xcode cannot figure out what I want to do. If I change the line (in the comments) to what the comment says, it works.
Can anyone help me in achieving what I want?
I don't see anything wrong with your code, but the compiler is crashing when compiling it. That should definitely be reported to Apple.
One workaround for this seems to be to simply declare Weak as a struct instead of a class. This compiles just fine:
struct Weak<T: AnyObject> {
weak var value : T?
init (value: T) {
self.value = value
}
}
protocol CSLocationServicesDelegate : class{
}
class conformance : CSLocationServicesDelegate{
}
class Dispatcher{
var dispatchArray = Array<Weak<CSLocationServicesDelegate>>()
func add( delegate : CSLocationServicesDelegate!){
dispatchArray.append(Weak(value: delegate));
}
func remove(obj : CSLocationServicesDelegate!){
dispatchArray.filter { (weakRef : Weak<CSLocationServicesDelegate>) -> Bool in
return weakRef.value != nil
}
}
}

Swift generic class type both subclass and conforms to protocol

I'm trying to write a generic class in Swift who's generic type both inherits from a class and conforms to a protocol. However, the following code results in a compiler crash with Segmentation fault: 11.
protocol Protocol {
var protocolProperty: Any? { get }
}
class Class {
var classProperty: Any?
}
class GenericClass<T: Class where T: Protocol> {
var genericProperty: T?
func foo() {
let classProperty: Any? = genericProperty!.classProperty
// This is the culprit
let protocolProperty: Any? = genericProperty!.protocolProperty
}
}
Commenting out the access to the protocol property allows the program to compile. There is no way to access anything from the protocol without the compiler crashing. Is there a workaround to creating a generic class that works like this?
As MikeS notes, you should open a radar for the crash. It should never crash.
But the solution is to focus on what protocol (i.e. list of methods) you actually need T to conform to rather than getting wrapped up in the class. For instance:
protocol WhatGenericClassHolds : Protocol {
var classProperty: Any? { get }
}
class GenericClass<T: WhatGenericClassHolds> { ... }
There is a problem in your declaration. conform your class to the protocol as below
protocol A {
var somePropertyInt : Int? {get }
}
class B:A {
var someProperty : String?
var somePropertyInt:Int?;
}
class GenericClass<T: B where T: A > {
var someGenericProperty : T?
func foo() {
println(someGenericProperty!.someProperty)
println(someGenericProperty!.somePropertyInt)
}
}
var someGen = GenericClass()
someGen.someGenericProperty?.somePropertyInt
someGen.someGenericProperty?.someProperty

Resources