2015-08-01 11 views
8
protocol Parent { 
    var children: [AnyObject] { get set } 
} 

class Foo { 
} 

class Bar: Parent { //error happens here 
    var children = [Foo]() 

    init() {} 
} 

otrzymuję błąd „Type«Przedmiot»nie jest zgodny z protokołem«macierzystego». Powód otrzymuję ten błąd jest, bo zdefiniowano dzieci na tablicę Foo zamiast AnyObject. Czy jest jakiś sposób mogę dokonać tej pracy?Czy moja klasa może zastąpić typ właściwości protokołu w Swift?

Odpowiedz

6

Wymaganie AnyObject w protokole oznacza tablicę musi móc przyjąć AnyObject wpisy children. Wygląda jednak na to, że chcesz, aby dzieci miały tylko obiekty tylko Foo.

Zamiast tego można dać Protokołu associated type:

protocol Parent { 
    associatedtype Child 
    var children: [Child] { get set } 
} 

class Foo { } 

class Bar: Parent { 
    var children = [Foo]() 
    init() {} 
} 
+0

Dokładnie to, czego potrzebowałem. Jestem fanem sprawdzania typów w Swift, ale czasami zmusza cię to do stworzenia mnóstwa kodu. Mam wiele zajęć w moim oprogramowaniu i muszę osobno sprawdzić każdy z nich, gdy wszystkie mają gwarancję, że ta sama właściwość może być frustrująca. – MAH

+1

@MAH Można również użyć protokołów, aby zapewnić wspólną funkcjonalność obiektów. Jeśli 'Dziecko' jest protokołem, to' var children: [Dziecko] 'może być spełnione przez dowolną tablicę elementów, które są zgodne z' Child'. Możesz uogólniać funkcjonalność i unikać sprawdzania spraw oddzielnie! – jtbandes

+0

Programowanie oparte na protokole (https://developer.apple.com/videos/wwdc/2015/?id=408) jest warte obejrzenia. – jtbandes

1

Jeżeli protokół deklaruje, że jest getter i setter typu [AnyObject] niż oznacza to, że nie muszą być takie getter i setter, nie podtypem tej klasy.

Twój kod będzie logicznie źle - ponieważ byłbyś w stanie ustawić, na przykład jakiś [Int] (protokół mówi, że jest to możliwe) do zmiennej typu [Foo] (klasa ma tylko ten var)

To jest właściwie jedyna właściwa droga.

protocol Parent { 
    var children: [AnyObject] { get set } 
} 

class Foo { 
} 

class Bar: Parent { //error happens here 
    var children = [AnyObject]() 

    init() {} 
} 

W szybkich typach 2.0 może być inna opcja.

0

Nie można zmienić typu właściwości.

Dodaj to do swojej klasy bar:

var childrenObject: Foo { 
    get { 
     return self.children as! Foo 
    } 
} 
2

Jeśli zawsze chcesz tablicę typu AnyObject trzeba określić go w swojej klasie:

class Bar: Parent { 
    var children = [AnyObject]() 
    init() {} 
} 

ale jeśli możesz użyj bardziej szczegółowego protokołu z typealias możesz przepisać protokół jak:

protocol Parent { 
    // in Swift 1 and 2: use `typealias` instead of `associatedtype` 
    associatedtype T: AnyObject // this makes sure that all instances in the array are definitely of type `AnyObject`/classes 
    var children: [T] { get set } 
} 

ten sposób Państwa byłego zgodności swoich prac klasowych, ale trzeba wziąć pod uwagę, że protokół ten może być stosowany jedynie jako ogólny przymusu, a więc tylko w funkcji i ogólnych deklaracji:

// --- this does work 
func someFunc<T: Parent, U: Parent>(p1: T, p2: U) { /* ... */ } 

class SomeClass<T: Parent> { /* ... */ } 


// --- this doesn't work 
let parent: Parent 
let array: [Parent] 
// here you can only use types which conform to the protocol 
// but not the protocol itself as generic arguments 
let something = SomeClass<Parent>() 
0

alternatywna do odpowiedzi protokołu, które mogą dać niektóre korzyści, których nie ma protokół.

class Parent<T : RawRepresentable> where T.RawValue == Int { 
    var value : T 

    init(withValue v : T) { 
     self.value = v 
    } 
} 

enum testOne : Int { 
    case one 
    case two 
} 

enum testTwo : Int { 
    case three 
    case four 
} 

class ChildOne : Parent<testOne> {} 

class ChildTwo : Parent<testTwo> {} 

let c1 = ChildOne(withValue: testOne.one) 
print(c1.value) 
let c2 = ChildTwo(withValue: testTwo.three) 
print(c2.value) 

pokrewne: How in Swift specify type constraint to be enum?

Powiązane problemy