Check if a func exists in Swift - swift

I wish to check if a func exists before I call it. For example:
if let touch: AnyObject = touches.anyObject() {
let location = touch.locationInView(self)
touchMoved(Int(location.x), Int(location.y))
}
I would like to call touchMoved(Int, Int) if it exists. Is it possible?

You can use the optional chaining operator:
This seems to only work with ObjC protocols that have #optional functions defined. Also seems to require a cast to AnyObject:
import Cocoa
#objc protocol SomeRandomProtocol {
#optional func aRandomFunction() -> String
#optional func anotherRandomFunction() -> String
}
class SomeRandomClass : NSObject {
func aRandomFunction() -> String {
return "aRandomFunc"
}
}
var instance = SomeRandomClass()
(instance as AnyObject).aRandomFunction?() //Returns "aRandomFunc"
(instance as AnyObject).anotherRandomFunction?() //Returns nil, as it is not implemented
Whats weird is that in the example above, the protocol "SomeRandomProtocol" is not even declared for "SomeRandomClass"... yet without the protocol definition, the chaining operator gives an error-- in the playground at least. Seems like the compiler needs a prototype of the function declared previously for the ?() operator to work.
Seems like maybe there's some bugs or work to do there.
See the "swift interoperability in depth" session for more info on the optional chaining operator and how it works in this case.

Related

In Swift, how can you test if an object implements an optional protocol method which differs by signature without actually calling that method?

Using Swift, is it possible to test if an object implements an optional protocol method without actually calling that method? This works except for cases where the optional methods differ only by their signature.
Consider this code...
#objc public protocol TestDelegate : AnyObject {
#objc optional func testx()
#objc optional func test(with string:String)
#objc optional func test(with2 int:Int)
}
let delegate:TestDelegate? = nil
if let _ = delegate?.test(with:) {
print("supports 'test(with:)'")
}
if let _ = delegate?.testx {
print("supports 'testx'")
}
If you paste the above in a playground, it works as expected.
However, if you change testx to test, it no longer works.
Likewise, if you change test(with2) to test(with) then that won't work either.
Is there any way to test for those methods that only differ by signature?
Hey MarqueIV for checking the optional you can use inbuilt function
func responds(to aSelector: Selector!) -> Bool
Returns a Boolean value that indicates whether the receiver implements or inherits a method that can respond to a specified message.
The application is responsible for determining whether a false response should be considered an error.
You cannot test whether an object inherits a method from its superclass by sending responds(to:) to the object using the super keyword.
This method will still be testing the object as a whole, not just the superclass’s implementation.
Therefore, sending responds(to:) to super is equivalent to sending it to self.
Instead, you must invoke the NSObject class method instancesRespond(to:) directly on the object’s superclass, as illustrated in the following code fragment.
Listing 1
if( [MySuperclass instancesRespondToSelector:#selector(aMethod)] ) {
// invoke the inherited method
[super aMethod];
}
You cannot simply use [[self superclass] instancesRespondToSelector:#selector(aMethod)] since this may cause the method to fail if it is invoked by a subclass.
Note that if the receiver is able to forward aSelector messages to another object, it will be able to respond to the message, albeit indirectly, even though this method returns false.
Parameters
aSelector
A selector that identifies a message.
Returns
true if the receiver implements or inherits a method that can respond to aSelector, otherwise false.
SDKs iOS 2.0+, macOS 10.0+, tvOS 9.0+, watchOS 2.0+
As also shown in How do I resolve "ambiguous use of" compile error with Swift #selector syntax?, you can explicitly coerce a function reference to its expected type in order to resolve such ambiguities.
The only difference being, as such function references are to #optional protocol requirements done through optional chaining, you need to coerce to the optional type of the function. From there, you can do a comparison with nil in order to determine if both the delegate is non-nil, and it implements the given requirement.
For example:
import Foundation
#objc public protocol TestDelegate : AnyObject {
#objc optional func test()
// Need to ensure the requirements have different selectors.
#objc(testWithString:) optional func test(with string: String)
#objc(testWithInt:) optional func test(with int: Int)
}
class C : TestDelegate {
func test() {}
func test(with someString: String) {}
func test(with someInt: Int) {}
}
var delegate: TestDelegate? = C()
if delegate?.test as (() -> Void)? != nil {
print("supports 'test'")
}
if delegate?.test(with:) as ((String) -> Void)? != nil {
print("supports 'test w/ String'")
}
if delegate?.test(with:) as ((Int) -> Void)? != nil {
print("supports 'test w/ Int'")
}
// supports 'test'
// supports 'test w/ String'
// supports 'test w/ Int'
Note that I've given the test(with:) requirements unique selectors in order to ensure they don't conflict (this doesn't affect the disambiguation, only allowing class C to conform to TestDelegate).

Default Implementation of Objective-C Optional Protocol Methods

How can I provide default implementations for Objective-C optional protocol methods?
Ex.
extension AVSpeechSynthesizerDelegate {
func speechSynthesizer(synthesizer: AVSpeechSynthesizer, didFinishSpeechUtterance utterance: AVSpeechUtterance) {
print(">>> did finish")
}
}
Expectation: Whatever class that conforms to AVSpeechSynthesizerDelegate should run the above function whenever a speech utterance finishes.
You do it just exactly as you've implemented it. The difference ends up being in how the method is actually called.
Let's take this very simplified example:
#objc protocol FooProtocol {
optional func bar() -> Int
}
class Omitted: NSObject, FooProtocol {}
class Implemented: NSObject, FooProtocol {
func bar() -> Int {
print("did custom bar")
return 1
}
}
By adding no other code, I'd expect to have to use this code as such:
let o: FooProtocol = Omitted()
let oN = o.bar?()
let i: FooProtocol = Implemented()
let iN = i.bar?()
Where oN and iN both end up having type Int?, oN is nil, iN is 1 and we see the text "did custom bar" print.
Importantly, not the optionally chained method call: bar?(), that question mark between the method name in the parenthesis. This is how we must call optional protocol methods from Swift.
Now let's add an extension for our protocol:
extension FooProtocol {
func bar() -> Int {
print("did bar")
return 0
}
}
If we stick to our original code, where we optionally chain the method calls, there is no change in behavior:
However, with the protocol extension, we no longer have to optionally unwrap. We can take the optional unwrapping out, and the extension is called:
The unfortunate problem here is that this isn't necessarily particularly useful, is it? Now we're just calling the method implemented in the extension every time.
So there's one slightly better option if you're in control of the class making use of the protocol and calling the methods. You can check whether or not the class responds to the selector:
let i: FooProtocol = Implemented()
if i.respondsToSelector("bar") {
i.bar?()
}
else {
i.bar()
}
This also means you have to modify your protocol declaration:
#objc protocol FooProtocol: NSObjectProtocol
Adding NSObjectProtocol allows us to call respondsToSelector, and doesn't really change our protocol at all. We'd already have to be inheriting from NSObject in order to implement a protocol marked as #objc.
Of course, with all this said, any Objective-C code isn't going to be able to perform this logic on your Swift types and presumably won't be able to actually call methods implemented in these protocol extensions it seems. So if you're trying to get something out of Apple's frameworks to call the extension method, it seems you're out of luck. It also seems that even if you're trying to call one or the other in Swift, if it's a protocol method mark as optional, there's not a very great solution.

Swift 2: understanding AnyObject and Self

I couldn't find any good explanation to my questions so I'd like to ask you directly. First of all I'd like to refine my code in this post.
My problem is the protocol AnyObject and the Self type. I didn't implement AnyObject into my code because it is marked with #objc and I don't want any Objective-C stuff involved in my code (don't judge me for that). I also couldn't find any explanation about the Self type. It just worked as expected, but Xcode does not replace Self with the type the static function is called at.
Here is some example:
extension Int : Instance {}
Int.singleton { (customInstanceName) -> Self in 0 } // Self shall be replaced with Int
As you can see Xcode produces a Self instead an Int. Is there any chance I could fix this? Am I right that Self does return the dynamicType and my implementation is fine as it is in my post above? I would really appreciate any good explanation about the Self type.
As you have seen in my code. I am using a custom protocol to check whether my instance is a class or not. Is there any other shiny implementation to check my instances if they are classes or structure types, or am I forced to use AnyObject if I want to get rid of my ClassInstance protocol?
Thank you for your time.
UPDATE:
protocol Test {}
class A : Test {}
struct B : Test {}
let aClass : Test = A()
let aStruct : Test = B()
if let someClass = aClass as? AnyObject {
print(someClass) // only this will print
}
if let someStruct = aStruct as? AnyObject {
print(someStruct)
}
This will work, but AnyObject is still marked as an #objc protocol.
The Self type can be only used in protocols where it is a implicit typealias of the type which conforms to it:
protocol Testable {
func test() -> Self
}
If you want to conform to this protocol you than have to replace Self with the name of the type. For instance:
struct Product: Testable {
func test() -> Product {
return Product()
}
}
Important Edit:
As DevAndArtist pointed out in the comments there is a working class check in Swift 1.2 (without automatic bridging to Objective C) but not Swift 2 (Xcode 7 beta 3; probably a bug):
if instance.dynamicType is AnyClass {
// instance is a class
} else {
// instance is not a class
}
You can see workaround (mainly) for Swift 2 below.
End Edit
With respect to classes you should use AnyObject if you want to keep it simple but you can also use reflection which would be much more effort.
Below you can see some reflection results of string interpolations (only the first few characters):
"\(reflect(classType))" // Swift._ClassMirror
"\(reflect(0))" // Swift._LeafMirror
"\(reflect(enumType))" // Swift._EnumMirror
"\(reflect(structure))" // Swift._StructMirror
"\(reflect([0, 4]))" // Swift._ArrayTypeMirror
"\(reflect(NSDate()))" // Foundation._NSDateMirror
"\(reflect(NSURLRelationship.Contains))" // Swift._EnumMirror
"\(reflect(Int?(2)))" // Swift._OptionalMirror
As you can see enums are consistent if they are not defined in the Swift standard library (unfortunately also Optional...). So you can distinguish also structs and enums:
public enum Type {
case Enum, Class, Struct
}
public func getType<T>(anything: T) -> Type {
if anything is AnyObject {
return .Class
}
if "\(reflect(anything))".hasPrefix("Swift._EnumMirror") {
return .Enum
}
return .Struct
}
So for a better result you have to put some effort into it to differentiate between all the different cases.
But the easiest way to distinguish only between reference types and value types (aka classes and structs/enums) is still (unfortunately only works for own declared structs and not built in types because they can be bridged to Objective C; I'm working on it...):
if instance is AnyObject {}
// or: if instance is of type Any
if let classInstance = instance as? AnyObject {}

How to represent an optional Bool (Bool?) in Objective-C?

I am trying to write a protocol in swift
#objc protocol RestAPIManagerDelegate {
optional func credentialValidated(isValid: Bool?)
}
But I am getting following error:
'Method cannot be marked #objc because the type of the parameter cannot be represented in Objective-C'
Any suggestion?
The problem is this type declaration:
`isValid: Bool?`
That is perfectly fine in Swift. But you cannot expose it to Objective-C, because Objective-C does not have any notion of an Optional BOOL - a BOOL in Objective-C is basically just a number, a primitive C datatype (what we call a scalar).
Here's another way of looking at it. In an interchange with Objective-C, you can use a Swift Optional anywhere that Objective-C can say nil - indeed, to a large extent Swift Optional exists exactly in order to deal with the possibility that Objective-C will say nil or that you might need to say nil to Objective-C. But a BOOL in Objective-C can never be nil - it can only be YES or NO (Swift true or false).
So you have three choices:
Take away the #objc that exposes all this to Objective-C
Remove the Optional and just declare that type a Bool
Use an object type. For example, declare the type as AnyObject? (or NSNumber?). This will work because Swift will bridge a Bool to an NSNumber (including as it passes into an AnyObject), and Objective-C will deal just fine with an Optional AnyObject or Optional NSNumber because those are object types, not scalars.
Object-C does not have the concept of optionals, try to remove the "?" from your declaration
It's OK to use NSNumber? instead, but there is another way.
You can create OptionalBool enum and use it instead of Bool? for compatibility with Objective-C.
Creating OptionalBool enum in Swift code:
#objc enum OptionalBool: Int {
case none
case yes
case no
}
#objc protocol RestAPIManagerDelegate {
#objc optional func credentialValidated(isValid: OptionalBool)
}
Using OptionalBool in Objective-C code:
#interface RestAPIManagerHandler () <RestAPIManagerDelegate>
#end
#implementation RestAPIManagerHandler
- (void)credentialValidatedWithIsValid:(enum OptionalBool)isValid {
switch (isValid) {
case OptionalBoolYes:
NSLog(#"TRUE");
break;
case OptionalBoolNo:
NSLog(#"FALSE");
break;
case OptionalBoolNone:
NSLog(#"NULL");
break;
}
}
#end
Swift Bool are converted in NSNumber so for example if a Swift method returns [Bool] and if you receive this array in Objective-C code, it become a NSArray <NSNumber *>. And if you give this array to a Swift method which receives a [Bool] as parameter, the conversion will be done automatically.
If you are wanting to just do a protocol in Swift, for use within Swift, without optionals you can do this:
public protocol Note {
var content: [ContentType] {get}
func insertNote(note: Note) -> Bool
}
That will force a class to implement a method that returns a Bool and have an array of some class called ContentType.
If you want to make the method optional, you must specify the objc keyword as you have done, regardless if you are interoperating with Objective-C or not. At that point, everything else should work in your example.
#objc protocol RestAPIManagerDelegate {
optional func credentialValidated(isValid: Bool?)
}
From Apples documentation:
Optional protocol requirements can only be specified if your protocol is marked with the #objc attribute.
This attribute indicates that the protocol should be exposed to Objective-C code and is described in Using Swift with Cocoa and Objective-C. Even if you are not interoperating with Objective-C, you need to mark your protocols with the #objc attribute if you want to specify optional requirements.
Note also that #objc protocols can be adopted only by classes, and not by structures or enumerations. If you mark your protocol as #objc in order to specify optional requirements, you will only be able to apply that protocol to class types.
The example given by Apple:
#objc protocol CounterDataSource {
optional func incrementForCount(count: Int) -> Int
optional var fixedIncrement: Int { get }
}

What's the difference between a protocol extended from AnyObject and a class-only protocol?

Both this declaration
protocol SomeProtocol : AnyObject {
}
and this declaration
protocol SomeProtocol : class {
}
seem to make it so that only classes can conform to this protocol (i.e. that the instances of the protocol are references to objects), and have no other effects.
Is there any difference between them? Should one be preferred over the other? If not, why is there two ways to do the same thing?
I am using the latest released Xcode 6.3.1.
This was answered by an official Swift developer (Slava_Pestov) on the Swift forums. Here is the summary:
You should use AnyObject (protocol SomeProtocol: AnyObject).
AnyObject and class are equivalent. There is no difference.
class will eventually be deprecated.
Regarding the answer https://forums.swift.org/t/class-only-protocols-class-vs-anyobject/11507/4, this answer is deprecated. These words are the same now.
DEPRECATED
Update: After consulting with the powers that be, the two definitions are supposed to be equivalent, with AnyObject being used as a stand-in while class was being finished. In the future the latter will obviate the former but, for now, they do present a few minor differences.
The difference lies in the semantics of #objc declarations. With AnyObject, the expectation is that conforming classes may or may not be proper Objective-C objects, but the language treats them as such anyway (in that you lose static dispatch sometimes). The takeaway from this is that you can treat an AnyObject et al. protocol constraint as a way to ask for #objc member functions as shown in the example in documentation for AnyObject in the STL:
import Foundation
class C {
#objc func getCValue() -> Int { return 42 }
}
// If x has a method #objc getValue()->Int, call it and
// return the result. Otherwise, return nil.
func getCValue1(x: AnyObject) -> Int? {
if let f: ()->Int = x.getCValue { // <===
return f()
}
return nil
}
// A more idiomatic implementation using "optional chaining"
func getCValue2(x: AnyObject) -> Int? {
return x.getCValue?() // <===
}
// An implementation that assumes the required method is present
func getCValue3(x: AnyObject) -> Int { // <===
return x.getCValue() // x.getCValue is implicitly unwrapped. // <===
}
The same example falls over immediately if you change that to a class-deriving protocol:
import Foundation
protocol SomeClass : class {}
class C : SomeClass {
#objc func getCValue() -> Int { return 42 }
}
// If x has a method #objc getValue()->Int, call it and
// return the result. Otherwise, return nil.
func getCValue1(x: SomeClass) -> Int? {
if let f: ()->Int = x.getCValue { // <=== SomeClass has no member 'getCValue'
return f()
}
return nil
}
// A more idiomatic implementation using "optional chaining"
func getCValue2(x: SomeClass) -> Int? {
return x.getCValue?() // <=== SomeClass has no member 'getCValue'
}
// An implementation that assumes the required method is present
func getCValue3(x: SomeClass) -> Int { // <===
return x.getCValue() // <=== SomeClass has no member 'getCValue'
}
So it seems class is a more conservative version of AnyObject that should be used when you only care about reference semantics and not about dynamic member lookups or Objective-C bridging.
In the Swift programming language guide for protocols, under the Class-Only Protocols section. It only mentioned AnyObject, but not class.
You can limit protocol adoption to class types (and not structures or enumerations) by adding the AnyObject protocol to a protocol’s inheritance list.
protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {
// class-only protocol definition goes here
}
For that reason, I will suggest using AnyObject over class for new code or new project. Other than that, I don't see any obvious difference between them.
From 2021, Xcode 12.5, Big Sur OS:
Usage of class is deprecated by apple.
Use AnyObject instead.
Happy Coding.
AnyObject is a protocol to which all classes implicitly conform (source). So I would say there is no difference: you can use either to require class constraint.
If you open the help (alt-click) in Xcode 9 for class in a line such as protocol P: class {}, you will get typealias AnyObject.
Thus, the code compiled (in Swift 4) will be the same whether you constrain the protocol to class or AnyObject.
That said, there is also the question of style and future options — a future Swift version might want to treat class and AnyObject differently in some subtle way, even if that is not the case right now.
(Edit: This has finally happened in Swift 5.4/Xcode 12.5.)
I misspoke before. #MartinR should really answer this, since he's the one who corrected me and provided the correct information.
The real difference is that a protocol with the class qualifier can only be applied to a class, not a struct or enum.
Martin, why don't you answer and the OP can accept your answer?