可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have the following code. How can I resolve the error in the last line?
protocol Animal { func walk() } struct Cat: Animal { func walk() {} init() { } } var obj: Any = Cat() var cat = obj as Animal // ERROR: cannot downcast from Any to unrelated type Animal
回答1:
Update: This has been fixed in Swift 1.2+ (Xcode 6.3+). The Xcode 6.3 beta release notes say:
Dynamic casts (“as!", “as?" and “is”) now work with Swift protocol types, so long as they have no associated types.
You can only check for protocol conformance (which includes is
, as
, and as?
) with an @objc
protocol. Animal
is not @objc
.
See the Checking for Protocol Conformance section of the Swift book.
NOTE
You can check for protocol conformance only if your protocol is marked with the @objc attribute
回答2:
You can workaround it by doing
var cat = obj as Cat as Animal
but this workaround is almost useless... because you need to know the type of obj
first
Edit:
As @newacct point out, it is not bug, see his answer for more information
xcrun swift Welcome to Swift! Type :help for assistance. 1> 2> @objc protocol Animal { 3. func walk() 4. } @objc class Cat: Animal { func walk() {} init() { } } var obj: AnyObject = Cat() var cat = obj as Animal 5> 6> @objc class Cat: Animal { 7. func walk() {} 8. 9. init() { } 10. } 11> 12> var obj: AnyObject = Cat() obj: Cat = {} 13> 14> var cat = obj as Animal cat: Cat = {} 15>
Animal
protocol need @objc
attribute and Cat
need to be @objc class
.
回答3:
My approach
@objc protocol Animal { func walk() } @objc class DummyAnimal: Animal { func walk() { } } @objc class Cat: DummyAnimal { override func walk() { print("meow") } override init() { } } var obj: Any = Cat() var cat = obj as DummyAnimal cat.walk()
回答4:
As far as I have been able to observe, AnyObject
can only be downcastAny
can only be downcast to types (class or otherwise), it is not possible to cast them to a protocol.
I don't know if I would qualify this as a bug or not, if this holds then perhaps it was implemented this way for a good reason - but @Bryan's workaround (casting to a type first and then to a protocol) at least "resolves the error"!