Init class deriving from protocol - swift

I've got a class deriving from a simple protocol. It looks like this:
protocol Interface {
func f() -> Void;
}
class TestInterface : Interface {
var arr: [Int] = [];
func f() {
// stuff
}
}
Unfortunately, I can't create this class as Swift has it has no initializers (although the default one would blatantly suffice).
However, the more serious problem is trying to define the initializer. Initially I tried to define an empty initializer. Swift told me that this was illegal because I did not call the super initializer (even though it's a protocol...). Fine, I thought. I called super.init(). Swift then told me this was illegal because the base is a protocol and not a class, so it has no init function. So I can't define an init function because I must call a nonexistent init function inside my own init function. And the normal init function is randomly unavailable for no good reason.
How the hell can I create an instance of my super simple class?

This is actually a totally unrelated issue. The protocol actually used to be a class. For an unrelated reason, the module that this class was imported from crashed the Swift compiler, and corrupted the metadata. So when Swift came to read the metadata for this class/protocol, it was inconsistent and confused the compiler.
As soon as I resolved the issue with the source module (and actually noticed it, thanks crappy XCode error reporting) this was no longer an issue for me.

Related

Workaround to bridge a *generic* protocol to Objective-C?

Let's say that we have the following Objective-C API:
- (id)foo:(Protocol *)proto;
Which is imported into Swift as:
func foo(_ proto: Protocol) -> Any
Yep, it's one of those things that gives us a proxy object. These tend to be annoying to use in Swift, so let's say we want to make a wrapper around this thing to make it a bit friendlier. First we define a couple of Objective-C-compatible protocols:
#objc protocol Super {}
#objc protocol Sub: Super {}
Now, we define a function that takes a protocol conforming to Super and passes it along to foo(), and then we call it with Sub as the parameter to see if it works:
func bar<P: Super>(proto: P.Type) {
let proxy = foo(proto)
// do whatever with the proxy
}
bar(proto: Sub.self)
Well, this doesn't compile. The error message given is:
error: cannot convert value of type 'P.Type' to expected argument type 'Protocol'
Here's some stuff that does (mostly) compile:
func bar<P: Super>(proto: P.Type) {
// when called with 'Sub.self' as 'proto':
print(type(of: proto)) // Sub.Protocol
print(type(of: Sub.self)) // Sub.Protocol
print(proto == Sub.self) // true
let proxy1 = foo(Sub.self) // compiles, runs, works
let proxy2 = foo(proto) // error: cannot convert value of type 'P.Type' to expected argument type 'Protocol'
}
Okay, it's the same as Sub.self in almost every way except that I can't pass it to something requiring an Objective-C protocol. Hmm.
The problem is that, although the fact that Sub conforms to Super means that it must be an Objective-C protocol, the compiler isn't realizing this. Can we work around that and get it bridged manually? Well, let's take a look at Protocol's interface, to see if there's anything that we can...
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0)
#interface Protocol : NSObject
#end
Oh. Hrm.
Well, the fact that Protocol is a full-fledged NSObject subclass suggests that this is all probably the work of my bestest favoritest feature, the magical Swift<->Objective-C bridge that performs non-trivial conversions on things without it being obvious what is going on. Well, this gives me an idea, at least; I should be able to manually invoke the bridge by casting to AnyObject and hopefully get at the Protocol object that way maybe by as!ing it or something. Does it work?
print(Sub.self as AnyObject) // <Protocol: 0x012345678>
Well, that's promising. And when I try it on my generic parameter?
print(proto as AnyObject) // Terminated due to signal: SEGMENTATION FAULT (11)
Oh, come on.
I suspect this is probably a bug in the compiler, and I plan to test a few things to determine whether that's the case, but since the Swift sources take a geologic age to compile, I figured I'd post this here while I'm waiting. Anyone have any insight and/or workarounds on what is going on here?
I know it's not pretty and "Swifty", exactly, but getting the Objective-C Protocol as appropriate for passing into foo can be achieved using NSProtocolFromString as follows:
let proxy2 = foo(NSProtocolFromString(String(reflecting: proto))!)
where String(reflecting:) is a useful way to get the fully qualified type name suitable for resolving via NSProtocolFromString.
I'd say the crash you encountered is a bug.
Okay, after investigating this a bit more, I've determined that it is indeed a compiler bug, and have filed a report on it: SR-8129. What appears to be happening is that the Swift compiler falsely assumes that proto will always be a metatype of a concrete class type, so it performs the bridging by emitting a call to swift_getObjCClassFromMetadata, which crashes when it encounters the protocol metatype. When Sub.self is explicitly cast to AnyObject, the compiler emits Swift._bridgeAnythingToObjectiveC<A>(A) -> Swift.AnyObject instead, which appears to dynamically determine the type of the object and bridge it accordingly.
With this in mind, the workaround becomes apparent: cast proto to Any first, to destroy the type information associated with the generic and force the compiler to emit Swift._bridgeAnythingToObjectiveC<A>(A) -> Swift.AnyObject. And indeed, this appears to work:
func bar<P: Super>(proto: P.Type) {
foo(proto as Any as AnyObject as! Protocol)
}
Not the prettiest thing out there, but probably preferable to looking up the protocol via string manipulation.

In swift, why can't I instantiate a protocol when it has an initialiser?

I understand that generally I cannot instantiate a protocol.
But if I include an initialiser in the protocol then surely the compiler knows that when the protocol is used by a struct or class later, it will have an init which it can use?
My code is as below and line:
protocol Solution {
var answer: String { get }
}
protocol Problem {
var pose: String { get }
}
protocol SolvableProblem: Problem {
func solve() -> Solution?
}
protocol ProblemGenerator {
func next() -> SolvableProblem
}
protocol Puzzle {
var problem: Problem { get }
var solution: Solution { get }
init(problem: Problem, solution: Solution)
}
protocol PuzzleGenerator {
func next() -> Puzzle
}
protocol FindBySolvePuzzleGenerator: PuzzleGenerator {
var problemGenerator: ProblemGenerator { get }
}
extension FindBySolvePuzzleGenerator {
func next() -> Puzzle {
while true {
let problem = problemGenerator.next()
if let solution = problem.solve() {
return Puzzle(problem: problem, solution: solution)
}
}
}
}
The line:
return Puzzle(problem: problem, solution: solution)
gives error: Protocol type 'Puzzle' cannot be instantiated
Imagine protocols are adjectives. Movable says you can move it, Red says it has color = "red"... but they don't say what it is. You need a noun. A Red, Movable Car. You can instantiate a Car, even when low on details. You cannot instantiate a Red.
But if I include an initialiser in the protocol then surely the compiler knows that when the protocol is used by a struct or class later, it will have an init which it can use?
Protocols must be adopted by classes, and there might be a dozen different classes that all adopt your Puzzle protocol. The compiler has no idea which of those classes to instantiate.
Protocols give us the power to compose interfaces without the complexity of multiple inheritance. In a multiple inheritance language like C++, you have to deal with the fact that a single class D might inherit from two other classes, B and C, and those two classes might happen to have methods or instance variables with the same name. If they both have a methodA(), and B::methodA() and C::methodA() are different, which one do you use when someone call's D's inherited methodA()? Worse, what if B and C are both derived from a common base class A? Protocols avoid a lot of that by not being directly instantiable, while still providing the interface polymorphism that makes multiple inheritance attractive.
I understand that I can't do it - I just want to understand why the
compiler can't do it?
Because protocols in Swift represent abstraction mechanism. When it comes to abstraction, you could think about it as a template, we don't have to care about the details of how it behaves or what's its properties; Thus it makes no sense to be able to create an object from it.
As a real world example, consider that I just said "Table" (as an abstracted level), I would be pretty sure that you would understand what I am talking about! nevertheless we are not mentioning details about it (such as its material or how many legs it has...); At some point if I said "create a table for me" (instantiate an object) you have the ask me about specs! and that's why the complier won't let you create object directly from a protocol. That's the point of making things to be abstracted.
Also, checking: Why can't an object of abstract class be created? might be helpful.
Unfortunately swift does not allow that even with such "hack"
You would need to use a class that confirms to that protocol as an object you refer to.
When you instantiate an object, the Operating System has to know how to allocate and deal with that kind of object in the memory: Is it a reference type (Classes)? Strong, weak or unowned reference? Or is it a value type (Structs, Strings, Int, etc)?
Reference types are stored in the Heap, while value types live in the Stack. Here is a thorough explanation of the difference between the two.
Only Reference and Value types (objects) can be instantiated. So, only the objects that conform to that protocol can then be instantiated, not the protocol itself. A protocol is not an object, it is a general description or schema of a certain behavior of objects.
As to Initialization, here what the Apple docs say:
Initialization is the process of preparing an instance of a class,
structure, or enumeration for use. This process involves setting an
initial value for each stored property on that instance and performing
any other setup or initialization that is required before the new
instance is ready for use.

swift method_exchangeImplementations not work

swift code is below:
func swizzleMethod()
{
let method:Method = class_getInstanceMethod(object_getClass(self), Selector("function1"))
self.function1()
let swizzledMethod:Method = class_getInstanceMethod(object_getClass(self), Selector("function2"))
method_exchangeImplementations(method, swizzledMethod)
self.function1()
}
func function1()
{
print("function1 log")
}
func function2()
{
print("function2 log")
}
it logs:
function1 log
function1 log
/////
my environment is swift based project, xcode7.2
This always run into the funtion1 method body, so I think it exchanged failed, this two method is in the same class, anyone know why?
I get the answer, add "dynamic" keyword in front of method name!!!
like this:
dynamic func function1()
{
print("function1 log")
}
dynamic func function2()
{
print("function2 log")
}
Reason:
Swift optimizes code to call direct memory addresses instead of looking up the method location at runtime as in Objective-C. so we need tell the code run treat it as Objective-C code.
Answer Detail:
Method swizzling is a technique that substitutes one method implementation for another. If you're not familiar with swizzling, check out this blog post. Swift optimizes code to call direct memory addresses instead of looking up the method location at runtime as in Objective-C. So by default swizzling doesn’t work in Swift classes unless we:
1. Disable this optimization with the dynamic keyword. This is the preferred choice, and the choice that makes the most sense if the codebase is entirely in Swift.
2. Extend NSObject. Never do this only for method swizzling (use dynamic instead). It’s useful to know that method swizzling will work in already existing classes that have NSObject as their base class, but we're better off selectively choosing methods with dynamic .
3. Use the #objc annotation on the method being swizzled. This is appropriate if the method we would like to swizzle also needs to be exposed to Objective-C code at the same time.
thanks to the article: 15 Tips to Become a Better Swift Developer

How to use a protocol with optional class methods in an extension with generic in Swift?

I am trying using extension for an existing class with class method like:
#objc public protocol MyProtocol {
optional class func foo() -> Int
}
And I am using this protocol in an extension with generic like:
extension MyClass {
public func bar<T: MyProtocol>() {
...
let x: Int = T.self.foo!() // if I do not use "self" or "!" here, I will have a compiler error
...
}
This should work but when I build it, Xcode says "Command /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc failed with exit code 1". If I do not use "optional" in the protocol, I do not need to unwrap the foo() in the extension and everything works well even if I remove the "self". Can anyone tell me why and how to make the optional work properly?
Thanks in advance.
It looks like you've found a (fairly obscure) bug in the Swift compiler that's causing it to crash.
Here's a reproduction that's all you need in a single file to crash swiftc:
import Foundation
#objc protocol P { optional class func f() }
func f<T: P>(t: T) { T.self.f?() }
(you don't need to call f for it to crash)
You should probably file a radar since the compiler crashing is never expected behavior no matter what your code.
If you tried to do this without the optional, it'll work (and you can even ditch the self). My guess is the implementation of generics doesn't currently account for the possibility of optional class-level functions.
You can do it without generics like this:
func f(p: MyProtocol) {
(p as AnyObject).dynamicType.foo?()
}
(there may even be a better way but I can't spot it).
You need the AnyObject cast because if you try to call .dynamicType.foo?() on p directly you get "accessing members of protocol type value 'MyProtocol.Type' is unimplemented". I wouldn't be surprised if the crash of the generic version is related to this.
I'd also say that its worth asking yourself whether you really need a protocol with optional methods (especially class-level ones) and whether there's a way to do what you want entirely statically using generics (as you're already semi-doing).

Swift : Why is the class method struck out

As long as a Swift class extends from NSObject we can pass it to the Objective-C runtime and ask it to introspect it for us.
We have three options:
class
classForCoder
classForKeyedArchiver
. . however class is struck out. (See image). Why is this?
That's because class is a keyword in Swift, therefore any valid method cannot be named class. In the same way you cannot create a method named for, while or other keyword.
I wasn't able to reproduce the strike-out with my methods, however, naming a method var (or other keyword) in obj-c makes it impossible to be called from Swift.
Edit
I was wrong. It's still possible to call class from Swift using
var clazz: AnyClass? = self.`class`()
However, then the compiler says:
'Class' is unavailable: use 'dynamicType' instead
So the answer by Edwin Vermeers is the correct one.
As you can see in the documentation, it's only available in Objective C and not in swift.
See: https://developer.apple.com/documentation/objectivec/nsobject/1571950-class
I think this is because the AnyObject gives you enough information (More than the NSObject)
for instance you can do NSStringFromClass(BaseObject) in swift instead of the NSStringFromClass([BaseObject class]) that you do in Objective C