Generics type constraint vs inheritance - ios

Is there a difference between these two function declarations?
func doSomething<T: UIViewController>(controller: T) {...}
vs.
func doSomething(controller: UIViewController) {...}
In Type Constraint Syntax section of the Apples Swift programming language book, there's this code sample:
func​ ​someFunction​<​T​: ​SomeClass​, ​U​: ​SomeProtocol​>(​someT​: ​T​, ​someU​: ​U​) {
// function body goes here
}
with this description:
The hypothetical function above has two type parameters. The first type parameter, T, has a type constraint that requires T to be a subclass of SomeClass. ...
So in which cases is it better to use generic function described above?

They are different, but in the way you are using them, they amount to pretty much exactly the same result.
The difference is that when you call the generic version, the compiler sets T statically to be whatever type is passed in as the argument. When calling methods on that argument, this makes almost no difference – either way the calls on its methods will be dynamically dispatched, and you can't touch any parts of T that aren't guaranteed to be available from the constraint.
But suppose you made a change to this method to not just take an argument, but also return one, of the same type:
// T here will take the type of whatever is going in/out of the function
// be that UIViewController or a subtype of it
func doSomethingGenerically<T: UIViewController>(controller: T) -> T {
// some logic that results in a new controller being returned
}
// here the return type is fixed to be UIViewController
func doSomethingViaBaseClass(controller: UIViewController) -> UIViewController {
// some logic that results in a new controller being returned
}
Now, suppose you had a subclass of UIViewController that you were passing in, like so:
let subClass: MyUIViewController = ...
let controller1 = doSomethingGenerically(subClass)
let controller2 = doSomethingViaBaseClass(subClass)
Here, the type of the variable controller1 will be MyUIViewController, because that is what was passed in to the function so that is what T is. But the type of the variable controller2 will be UIViewController because that is the fixed type that doSomethingViaBaseClass returns.
Note, this doesn't mean the object they reference will be different - that depends on what the body of the function implements. It's just the type of the variables referring to it that will change.
There are other subtle differences but this is the main one to know about. In the case of structs, however, there are more differences worth noting. As it happens I wrote an article about them yesterday that might help.

Related

Associatedtype depends on protocol [duplicate]

Why doesn't this Swift code compile?
protocol P { }
struct S: P { }
let arr:[P] = [ S() ]
extension Array where Element : P {
func test<T>() -> [T] {
return []
}
}
let result : [S] = arr.test()
The compiler says: "Type P does not conform to protocol P" (or, in later versions of Swift, "Using 'P' as a concrete type conforming to protocol 'P' is not supported.").
Why not? This feels like a hole in the language, somehow. I realize that the problem stems from declaring the array arr as an array of a protocol type, but is that an unreasonable thing to do? I thought protocols were there exactly to help supply structs with something like a type hierarchy?
Why don't protocols conform to themselves?
Allowing protocols to conform to themselves in the general case is unsound. The problem lies with static protocol requirements.
These include:
static methods and properties
Initialisers
Associated types (although these currently prevent the use of a protocol as an actual type)
We can access these requirements on a generic placeholder T where T : P – however we cannot access them on the protocol type itself, as there's no concrete conforming type to forward onto. Therefore we cannot allow T to be P.
Consider what would happen in the following example if we allowed the Array extension to be applicable to [P]:
protocol P {
init()
}
struct S : P {}
struct S1 : P {}
extension Array where Element : P {
mutating func appendNew() {
// If Element is P, we cannot possibly construct a new instance of it, as you cannot
// construct an instance of a protocol.
append(Element())
}
}
var arr: [P] = [S(), S1()]
// error: Using 'P' as a concrete type conforming to protocol 'P' is not supported
arr.appendNew()
We cannot possibly call appendNew() on a [P], because P (the Element) is not a concrete type and therefore cannot be instantiated. It must be called on an array with concrete-typed elements, where that type conforms to P.
It's a similar story with static method and property requirements:
protocol P {
static func foo()
static var bar: Int { get }
}
struct SomeGeneric<T : P> {
func baz() {
// If T is P, what's the value of bar? There isn't one – because there's no
// implementation of bar's getter defined on P itself.
print(T.bar)
T.foo() // If T is P, what method are we calling here?
}
}
// error: Using 'P' as a concrete type conforming to protocol 'P' is not supported
SomeGeneric<P>().baz()
We cannot talk in terms of SomeGeneric<P>. We need concrete implementations of the static protocol requirements (notice how there are no implementations of foo() or bar defined in the above example). Although we can define implementations of these requirements in a P extension, these are defined only for the concrete types that conform to P – you still cannot call them on P itself.
Because of this, Swift just completely disallows us from using a protocol as a type that conforms to itself – because when that protocol has static requirements, it doesn't.
Instance protocol requirements aren't problematic, as you must call them on an actual instance that conforms to the protocol (and therefore must have implemented the requirements). So when calling a requirement on an instance typed as P, we can just forward that call onto the underlying concrete type's implementation of that requirement.
However making special exceptions for the rule in this case could lead to surprising inconsistencies in how protocols are treated by generic code. Although that being said, the situation isn't too dissimilar to associatedtype requirements – which (currently) prevent you from using a protocol as a type. Having a restriction that prevents you from using a protocol as a type that conforms to itself when it has static requirements could be an option for a future version of the language
Edit: And as explored below, this does look like what the Swift team are aiming for.
#objc protocols
And in fact, actually that's exactly how the language treats #objc protocols. When they don't have static requirements, they conform to themselves.
The following compiles just fine:
import Foundation
#objc protocol P {
func foo()
}
class C : P {
func foo() {
print("C's foo called!")
}
}
func baz<T : P>(_ t: T) {
t.foo()
}
let c: P = C()
baz(c)
baz requires that T conforms to P; but we can substitute in P for T because P doesn't have static requirements. If we add a static requirement to P, the example no longer compiles:
import Foundation
#objc protocol P {
static func bar()
func foo()
}
class C : P {
static func bar() {
print("C's bar called")
}
func foo() {
print("C's foo called!")
}
}
func baz<T : P>(_ t: T) {
t.foo()
}
let c: P = C()
baz(c) // error: Cannot invoke 'baz' with an argument list of type '(P)'
So one workaround to to this problem is to make your protocol #objc. Granted, this isn't an ideal workaround in many cases, as it forces your conforming types to be classes, as well as requiring the Obj-C runtime, therefore not making it viable on non-Apple platforms such as Linux.
But I suspect that this limitation is (one of) the primary reasons why the language already implements 'protocol without static requirements conforms to itself' for #objc protocols. Generic code written around them can be significantly simplified by the compiler.
Why? Because #objc protocol-typed values are effectively just class references whose requirements are dispatched using objc_msgSend. On the flip side, non-#objc protocol-typed values are more complicated, as they carry around both value and witness tables in order to both manage the memory of their (potentially indirectly stored) wrapped value and to determine what implementations to call for the different requirements, respectively.
Because of this simplified representation for #objc protocols, a value of such a protocol type P can share the same memory representation as a 'generic value' of type some generic placeholder T : P, presumably making it easy for the Swift team to allow the self-conformance. The same isn't true for non-#objc protocols however as such generic values don't currently carry value or protocol witness tables.
However this feature is intentional and is hopefully to be rolled out to non-#objc protocols, as confirmed by Swift team member Slava Pestov in the comments of SR-55 in response to your query about it (prompted by this question):
Matt Neuburg added a comment - 7 Sep 2017 1:33 PM
This does compile:
#objc protocol P {}
class C: P {}
func process<T: P>(item: T) -> T { return item }
func f(image: P) { let processed: P = process(item:image) }
Adding #objc makes it compile; removing it makes it not compile again.
Some of us over on Stack Overflow find this surprising and would like
to know whether that's deliberate or a buggy edge-case.
Slava Pestov added a comment - 7 Sep 2017 1:53 PM
It's deliberate – lifting this restriction is what this bug is about.
Like I said it's tricky and we don't have any concrete plans yet.
So hopefully it's something that language will one day support for non-#objc protocols as well.
But what current solutions are there for non-#objc protocols?
Implementing extensions with protocol constraints
In Swift 3.1, if you want an extension with a constraint that a given generic placeholder or associated type must be a given protocol type (not just a concrete type that conforms to that protocol) – you can simply define this with an == constraint.
For example, we could write your array extension as:
extension Array where Element == P {
func test<T>() -> [T] {
return []
}
}
let arr: [P] = [S()]
let result: [S] = arr.test()
Of course, this now prevents us from calling it on an array with concrete type elements that conform to P. We could solve this by just defining an additional extension for when Element : P, and just forward onto the == P extension:
extension Array where Element : P {
func test<T>() -> [T] {
return (self as [P]).test()
}
}
let arr = [S()]
let result: [S] = arr.test()
However it's worth noting that this will perform an O(n) conversion of the array to a [P], as each element will have to be boxed in an existential container. If performance is an issue, you can simply solve this by re-implementing the extension method. This isn't an entirely satisfactory solution – hopefully a future version of the language will include a way to express a 'protocol type or conforms to protocol type' constraint.
Prior to Swift 3.1, the most general way of achieving this, as Rob shows in his answer, is to simply build a wrapper type for a [P], which you can then define your extension method(s) on.
Passing a protocol-typed instance to a constrained generic placeholder
Consider the following (contrived, but not uncommon) situation:
protocol P {
var bar: Int { get set }
func foo(str: String)
}
struct S : P {
var bar: Int
func foo(str: String) {/* ... */}
}
func takesConcreteP<T : P>(_ t: T) {/* ... */}
let p: P = S(bar: 5)
// error: Cannot invoke 'takesConcreteP' with an argument list of type '(P)'
takesConcreteP(p)
We cannot pass p to takesConcreteP(_:), as we cannot currently substitute P for a generic placeholder T : P. Let's take a look at a couple of ways in which we can solve this problem.
1. Opening existentials
Rather than attempting to substitute P for T : P, what if we could dig into the underlying concrete type that the P typed value was wrapping and substitute that instead? Unfortunately, this requires a language feature called opening existentials, which currently isn't directly available to users.
However, Swift does implicitly open existentials (protocol-typed values) when accessing members on them (i.e it digs out the runtime type and makes it accessible in the form of a generic placeholder). We can exploit this fact in a protocol extension on P:
extension P {
func callTakesConcreteP/*<Self : P>*/(/*self: Self*/) {
takesConcreteP(self)
}
}
Note the implicit generic Self placeholder that the extension method takes, which is used to type the implicit self parameter – this happens behind the scenes with all protocol extension members. When calling such a method on a protocol typed value P, Swift digs out the underlying concrete type, and uses this to satisfy the Self generic placeholder. This is why we're able to call takesConcreteP(_:) with self – we're satisfying T with Self.
This means that we can now say:
p.callTakesConcreteP()
And takesConcreteP(_:) gets called with its generic placeholder T being satisfied by the underlying concrete type (in this case S). Note that this isn't "protocols conforming to themselves", as we're substituting a concrete type rather than P – try adding a static requirement to the protocol and seeing what happens when you call it from within takesConcreteP(_:).
If Swift continues to disallow protocols from conforming to themselves, the next best alternative would be implicitly opening existentials when attempting to pass them as arguments to parameters of generic type – effectively doing exactly what our protocol extension trampoline did, just without the boilerplate.
However note that opening existentials isn't a general solution to the problem of protocols not conforming to themselves. It doesn't deal with heterogenous collections of protocol-typed values, which may all have different underlying concrete types. For example, consider:
struct Q : P {
var bar: Int
func foo(str: String) {}
}
// The placeholder `T` must be satisfied by a single type
func takesConcreteArrayOfP<T : P>(_ t: [T]) {}
// ...but an array of `P` could have elements of different underlying concrete types.
let array: [P] = [S(bar: 1), Q(bar: 2)]
// So there's no sensible concrete type we can substitute for `T`.
takesConcreteArrayOfP(array)
For the same reasons, a function with multiple T parameters would also be problematic, as the parameters must take arguments of the same type – however if we have two P values, there's no way we can guarantee at compile time that they both have the same underlying concrete type.
In order to solve this problem, we can use a type eraser.
2. Build a type eraser
As Rob says, a type eraser, is the most general solution to the problem of protocols not conforming to themselves. They allow us to wrap a protocol-typed instance in a concrete type that conforms to that protocol, by forwarding the instance requirements to the underlying instance.
So, let's build a type erasing box that forwards P's instance requirements onto an underlying arbitrary instance that conforms to P:
struct AnyP : P {
private var base: P
init(_ base: P) {
self.base = base
}
var bar: Int {
get { return base.bar }
set { base.bar = newValue }
}
func foo(str: String) { base.foo(str: str) }
}
Now we can just talk in terms of AnyP instead of P:
let p = AnyP(S(bar: 5))
takesConcreteP(p)
// example from #1...
let array = [AnyP(S(bar: 1)), AnyP(Q(bar: 2))]
takesConcreteArrayOfP(array)
Now, consider for a moment just why we had to build that box. As we discussed early, Swift needs a concrete type for cases where the protocol has static requirements. Consider if P had a static requirement – we would have needed to implement that in AnyP. But what should it have been implemented as? We're dealing with arbitrary instances that conform to P here – we don't know about how their underlying concrete types implement the static requirements, therefore we cannot meaningfully express this in AnyP.
Therefore, the solution in this case is only really useful in the case of instance protocol requirements. In the general case, we still cannot treat P as a concrete type that conforms to P.
EDIT: Eighteen more months of working w/ Swift, another major release (that provides a new diagnostic), and a comment from #AyBayBay makes me want to rewrite this answer. The new diagnostic is:
"Using 'P' as a concrete type conforming to protocol 'P' is not supported."
That actually makes this whole thing a lot clearer. This extension:
extension Array where Element : P {
doesn't apply when Element == P since P is not considered a concrete conformance of P. (The "put it in a box" solution below is still the most general solution.)
Old Answer:
It's yet another case of metatypes. Swift really wants you to get to a concrete type for most non-trivial things. [P] isn't a concrete type (you can't allocate a block of memory of known size for P). (I don't think that's actually true; you can absolutely create something of size P because it's done via indirection.) I don't think there's any evidence that this is a case of "shouldn't" work. This looks very much like one of their "doesn't work yet" cases. (Unfortunately it's almost impossible to get Apple to confirm the difference between those cases.) The fact that Array<P> can be a variable type (where Array cannot) indicates that they've already done some work in this direction, but Swift metatypes have lots of sharp edges and unimplemented cases. I don't think you're going to get a better "why" answer than that. "Because the compiler doesn't allow it." (Unsatisfying, I know. My whole Swift life…)
The solution is almost always to put things in a box. We build a type-eraser.
protocol P { }
struct S: P { }
struct AnyPArray {
var array: [P]
init(_ array:[P]) { self.array = array }
}
extension AnyPArray {
func test<T>() -> [T] {
return []
}
}
let arr = AnyPArray([S()])
let result: [S] = arr.test()
When Swift allows you to do this directly (which I do expect eventually), it will likely just be by creating this box for you automatically. Recursive enums had exactly this history. You had to box them and it was incredibly annoying and restricting, and then finally the compiler added indirect to do the same thing more automatically.
If you extend CollectionType protocol instead of Array and constraint by protocol as a concrete type, you can rewrite the previous code as follows.
protocol P { }
struct S: P { }
let arr:[P] = [ S() ]
extension CollectionType where Generator.Element == P {
func test<T>() -> [T] {
return []
}
}
let result : [S] = arr.test()

This is one thing I do not understand in Swift

Consider these lines:
I create a NSButton based class with this:
typealias onClickHandler = (NSTextfieldSuper)->Void
var onClick: onClickHandler?
When the user clicks on an instance of that button, I do this:
if (self.onClick != nil) {
onClick?(self)
}
I use that button later, from another class, with this:
let button = SuperButton()
button.onClick = { (textField: NSTextfieldSuper)->Void in
}
I am not sure if this is the correct syntax. I would like to process the button sent from the first closure on the parent class, where the button is created.
This was the only form I was able to type this without Xcode complaining. If this is correct, what is the purpose of this ->Void there? What could this possibly returning?
I just want to process that button sent.
By the way, as a bonus, I have to initialize several buttons with this, all running the same function. It would be nice to do something like
func doSomething () {
}
and then
let button = SuperButton()
button.onClick = doSomething
any ideas?
This was the only form I was able to type this without Xcode complaining. If this is correct, what is the purpose of this ->Void there? What could this possibly returning?
It is the same as in your typealias, in Swift a function type has the form:
(parameter definitions) -> return type
and functions which return nothing have a return type of Void (similar to C). The full form off a closure expression is:
{ (parameter definitions) ->return typeinbody}
Without any inference this expression provides the full type of the closure, and the -> Void Return type in your example specifies that your closure returns nothing. In your assignment this full type will be checked at compile time to conform to the type of onClick.
Now Swift will infer lots of stuff and there are various shorthands available for closure expressions, you will find that Swift accepts:
button.onClick = { textField in }
as well here with both the argument and return types of the closure being inferred.
By the way, as a bonus, [...] any ideas?
Just make the types match:
func doSomething(textField : NSTextfieldSuper) { }
button.onClick = doSomething
Unlike in (Objective-)C functions and closures (blocks in C) are interchangeable (as they are in plenty of other languages, C is the oddfellow here)
HTH

Swift generic class, inheritance and covariance

I'm faced with the problem of using generic class and inheritance.
Brief description of the problem:
I have a base class called BookPageDataSource and two inherited classes (ReadingBookPageDataSource and StarsBookPageDataSource) with different implementations.
Also, I have a generic class BookPageViewController that contains the generic parameter of this data source and two inherited classes (ReadingBookPageViewController and StarsBookPageViewController) from this class.
I need to write a method the return parameter of which is BookPageViewController<DataSource>.
// Data Sources
class BookPageDataSource { }
class ReadingBookPageDataSource: BookPageDataSource { }
class StarsBookPageDataSource: BookPageDataSource { }
// Controllers
class BookPageViewController<DataSource: BookPageDataSource>: UIViewController {
let dataSource: DataSource
init(dataSource: DataSource) {
self.dataSource = dataSource
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
return nil
}
}
final class ReadingBookPageViewController: BookPageViewController<ReadingBookPageDataSource> { }
final class StarsBookPageViewController: BookPageViewController<StarsBookPageDataSource> { }
// Communication
class Pager {
func currentPageController<DataSource>(at index: Int) -> BookPageViewController<DataSource> {
// for example
if index == 0 {
// How to remove the cast from the line below?
return readingPageController() as! BookPageViewController<DataSource>
}
return starsPageController() as! BookPageViewController<DataSource>
}
private func readingPageController() -> ReadingBookPageViewController {
return ReadingBookPageViewController(dataSource: ReadingBookPageDataSource())
}
private func starsPageController() -> StarsBookPageViewController {
return StarsBookPageViewController(dataSource: StarsBookPageDataSource())
}
}
The method currentPageController always crashes, because the DataSource is always equals to BookPageDataSource, not to ReadingBookPageDataSource or StarsBookPageDataSource.
Conceptual Discussion
Your concept for the architecture is flawed and this is leading to your issue.
Simple Generics Example
Here's a very simple example of a generic function, which just returns the value you give it:
func echo <T> (_ value: T) -> T { return value }
Because this function is generic, there is ambiguity about the type that it uses. What is T? Swift is a type-safe language, which means that ultimately there is not allowed to be any ambiguity about type whatsoever. So why is this echo function allowed? The answer is that when I actually use this function somewhere, the ambiguity about the type will be removed. For example:
let myValue = echo(7) // myValue is now of type Int and has the value 7
In the act of using this generic function I have removed the ambiguity by passing it an Int, and therefore the compiler has no uncertainty about the types involved.
Your Function
func currentPageController <DataSource> (at index: Int) -> BookPageViewController<DataSource>
Your function only uses the generic parameter DataSource in the return type, not in the input - how is the compiler supposed figure out what DataSource is?* I assume this is how you imagined using your function:
let pager = Pager()
let controller = pager.currentPageController(at: 0)
But now, what is the type of controller? What can you expect to be able to do with it? It seems that you're hoping that controller will take on the correct type based on the value that you pass in (0), but this is not how it works. The generic parameter is determined based on the type of the input, not the value of the input. You're hoping that passing in 0 will yield one return type, while 1 will yield a different one - but this is forbidden in Swift. Both 0 and 1 are of type Int, and the type is all that can matter.
As is usually the case with Swift, it is not the language/compiler that is preventing you from doing something. It is that you haven't yet logically formulated what is even is that you want, and the compiler is just informing you of the fact that what you've written so far doesn't make sense.
Solutions
Let's move on to giving you a solution though.
UIViewController Functionality
Presumably there is something that you wanted to use controller for. What is it that you actually need? If you just want to push it onto a navigation controller then you don't need it to be a BookPageViewController. You only need it to be a UIViewController to use that functionality, so your function can become this:
func currentPageController (at index: Int) -> UIViewController {
if index == 0 {
return readingPageController()
}
return starsPageController()
}
And you can push the controller that it returns onto a navigation stack.
Custom Functionality (Non-Generic)
If, however, you need to use some functionality which is specific to a BookPageViewController then it depends what it is you want to do. If there is a method on BookPageViewController like this:
func doSomething (input: Int) -> String
which doesn't make use of the generic parameter DataSource then probably you'll want to separate out that function into its own protocol/superclass which isn't generic. For example:
protocol DoesSomething {
func doSomething (input: Int) -> String
}
and then have BookPageViewController conform to it:
extension BookPageViewController: DoesSomething {
func doSomething (input: Int) -> String {
return "put your implementation here"
}
}
Now the return type of your function can be this non-generic protocol:
func currentPageController (at index: Int) -> DoesSomething {
if index == 0 {
return readingPageController()
}
return starsPageController()
}
and you can use it like this:
let pager = Pager()
let controller = pager.currentPageController(at: 0)
let retrievedValue = controller.doSomething(input: 7)
Of course, if the return type is no longer a UIViewController of any sort then you probably want to consider renaming the function and the related variables.
Custom Functionality (Generic)
The other option is that you can't separate out the functionality you need into a non-generic protocol/superclass because this functionality makes use of the generic parameter DataSource. A basic example is:
extension BookPageViewController {
func setDataSource (_ newValue: DataSource) {
self.dataSource = newValue
}
}
So in this case you really do need the return type of your function to be BookPageViewController<DataSource>. What do you do? Well, if what you really want is to use the setDataSource(_:) method defined above then you must have a DataSource object that you plan to pass in as an argument, right? If this is the case then we're making progress. Previously, you only had some Int value which you were passing into your function and the problem was that you couldn't specify your generic return type with that. But if you already have a BookPageDataSource value then it is at least logically possible for you to use this to specialize your
function.
What you say you want, however, is to just use an Int to get the controller at that index, regardless of what the DataSource type is. But if you don't care what the DataSource is of the returned BookPageViewController then how can you expect to set its DataSource to something else using the setDataSource(_:) method?
You see, the problem solves itself. The only reason you would need the return type of your function to be generic is if the subsequent functionality you need to make use of uses that generic type, but if this is the case then the controller you get back can't have just any old DataSource (you just wanted whichever one corresponds to the index you provide) - you need it to have exactly the type of DataSource which you plan to pass in when you use it, otherwise you're giving it the wrong type.
So the ultimate answer to your question is that, in the way that you were conceiving of it, there is no possible use for the function you were trying to construct. What's very cool about the way Swift is architected is that the compiler is actually able to figure out that logical flaw and prevent you from building your code until you've re-conceptualized it.
Footnote:
* It is possible to have a generic function which only uses the generic parameter in the return type and not in the input, but this won't help you here.

How to discriminate same method selector on Swift 3.0? [duplicate]

[NOTE This question was originally formulated under Swift 2.2. It has been revised for Swift 4, involving two important language changes: the first method parameter external is no longer automatically suppressed, and a selector must be explicitly exposed to Objective-C.]
Let's say I have these two methods in my class:
#objc func test() {}
#objc func test(_ sender:AnyObject?) {}
Now I want to use Swift 2.2's new #selector syntax to make a selector corresponding to the first of these methods, func test(). How do I do it? When I try this:
let selector = #selector(test) // error
... I get an error, "Ambiguous use of test()." But if I say this:
let selector = #selector(test(_:)) // ok, but...
... the error goes away, but I'm now referring to the wrong method, the one with a parameter. I want to refer to the one without any parameter. How do I do it?
[Note: the example is not artificial. NSObject has both Objective-C copy and copy: instance methods, Swift copy() and copy(sender:AnyObject?); so the problem can easily arise in real life.]
[NOTE This answer was originally formulated under Swift 2.2. It has been revised for Swift 4, involving two important language changes: the first method parameter external is no longer automatically suppressed, and a selector must be explicitly exposed to Objective-C.]
You can work around this problem by casting your function reference to the correct method signature:
let selector = #selector(test as () -> Void)
(However, in my opinion, you should not have to do this. I regard this situation as a bug, revealing that Swift's syntax for referring to functions is inadequate. I filed a bug report, but to no avail.)
Just to summarize the new #selector syntax:
The purpose of this syntax is to prevent the all-too-common runtime crashes (typically "unrecognized selector") that can arise when supplying a selector as a literal string. #selector() takes a function reference, and the compiler will check that the function really exists and will resolve the reference to an Objective-C selector for you. Thus, you can't readily make any mistake.
(EDIT: Okay, yes you can. You can be a complete lunkhead and set the target to an instance that doesn't implement the action message specified by the #selector. The compiler won't stop you and you'll crash just like in the good old days. Sigh...)
A function reference can appear in any of three forms:
The bare name of the function. This is sufficient if the function is unambiguous. Thus, for example:
#objc func test(_ sender:AnyObject?) {}
func makeSelector() {
let selector = #selector(test)
}
There is only one test method, so this #selector refers to it even though it takes a parameter and the #selector doesn't mention the parameter. The resolved Objective-C selector, behind the scenes, will still correctly be "test:" (with the colon, indicating a parameter).
The name of the function along with the rest of its signature. For example:
func test() {}
func test(_ sender:AnyObject?) {}
func makeSelector() {
let selector = #selector(test(_:))
}
We have two test methods, so we need to differentiate; the notation test(_:) resolves to the second one, the one with a parameter.
The name of the function with or without the rest of its signature, plus a cast to show the types of the parameters. Thus:
#objc func test(_ integer:Int) {}
#nonobjc func test(_ string:String) {}
func makeSelector() {
let selector1 = #selector(test as (Int) -> Void)
// or:
let selector2 = #selector(test(_:) as (Int) -> Void)
}
Here, we have overloaded test(_:). The overloading cannot be exposed to Objective-C, because Objective-C doesn't permit overloading, so only one of them is exposed, and we can form a selector only for the one that is exposed, because selectors are an Objective-C feature. But we must still disambiguate as far as Swift is concerned, and the cast does that.
(It is this linguistic feature that is used — misused, in my opinion — as the basis of the answer above.)
Also, you might have to help Swift resolve the function reference by telling it what class the function is in:
If the class is the same as this one, or up the superclass chain from this one, no further resolution is usually needed (as shown in the examples above); optionally, you can say self, with dot-notation (e.g. #selector(self.test), and in some situations you might have to do so.
Otherwise, you use either a reference to an instance for which the method is implemented, with dot-notation, as in this real-life example (self.mp is an MPMusicPlayerController):
let pause = UIBarButtonItem(barButtonSystemItem: .pause,
target: self.mp, action: #selector(self.mp.pause))
...or you can use the name of the class, with dot-notation:
class ClassA : NSObject {
#objc func test() {}
}
class ClassB {
func makeSelector() {
let selector = #selector(ClassA.test)
}
}
(This seems a curious notation, because it looks like you're saying test is a class method rather than an instance method, but it will be correctly resolved to a selector nonetheless, which is all that matters.)
I want to add a missing disambiguation: accessing an instance method from outside the class.
class Foo {
#objc func test() {}
#objc func test(_ sender: AnyObject?) {}
}
From the class' perspective the full signature of the test() method is (Foo) -> () -> Void, which you will need to specify in order to get the Selector.
#selector(Foo.test as (Foo) -> () -> Void)
#selector(Foo.test(_:))
Alternatively you can refer to an instance's Selectors as shown in the original answer.
let foo = Foo()
#selector(foo.test as () -> Void)
#selector(foo.test(_:))
In my case (Xcode 11.3.1) the error was only when using lldb while debugging. When running it works properly.

'ViewController -> () -> VIewController' does not have a member named 'view'

I was setting up BLKFlexibleHeightBar with swift. while I was writing var flexibleHeightBar = BLKFlexibleHeightBar(frame: CGRectMake(0, 0, self.view.frame.size.width, 100)), an error as the title occurred.
How can I solve this problem?
The frame is supposed to be a CGRect, and you are not providing one. Your frame: 0, 0, self.view.frame.size.width, 100 is just a series of numbers, not a CGRect. Swift has no idea what all those numbers are doing there. If you want a CGRect - and you do - you must say so:
frame: CGRectMake(0, 0, self.view.frame.size.width, 100)
The error is obviously related to your call to self.view, where, according to the error, the compiler thinks self is of type ViewController -> () -> ViewController, instead of what you probably expect it to be ViewController.
Where did you write this code?
If you wrote it in some init code or in a static func of your ViewController, then in that context self is not an instance of ViewController but something else. And given where you wrote that code, self.view does not represent you ViewController's instance's view property, probably because self isn't created yet.
You need to move your code from init() (where the self instance is being created but not ready yet) to viewDidLoad (once the ViewController's view was just created).
Technical explanation on the ViewController -> () -> ViewController type
If you want to get a bit more technical and understand why the compiler expect self to be of that type in the error you had, know that in Swift, an instance method is actually also exposed as a class method which takes an instance as parameter and return the instance method (that mechanism is called "currying").
For example the String class has an instance method hasPrefix whose type is String -> Bool. It is also exposed as a class method that expect a String instance and return that aforementioned instance method applied on that instance; so that String.hasPrefix is of type String -> String -> Bool, and String.hasPrefix("Hello world")("Hello") is strictly equivalent to "Hello world".hasPrefix("Hello") (yeah I know that can seems strange at first, but it makes sense). Of course in general you rarely (if ever) use this in your daily code, that's just a rarely used feature of Swift, but it's there.
Back to your context, you were in the init method of your ViewController. init() is in fact a (special) instance method (no static/class before init) that, in that case, takes no parameter (()) and will return a ViewController instance, so its type is () -> ViewController. This instance method can also be interpreted as a class method (on the ViewController class) whose type is ViewController -> () -> ViewController, because behind the scenes it will be called with an (uninitialized, freshly allocated) instance of ViewController and will return a function (init) that, once called (with no parameter, ()), will return the initialized instance of ViewController.
So that's where that ViewController -> () -> ViewController comes from in your error message above.

Resources