I am a Android developer, and I'm very new to Swift so please bear with me. I am trying to implement callback functions with Protocol in Swift. In Java I can create an Interface and make it an instance without linking it to any implementing class so that I can pass it around, for example:
public interface SomeListener {
void done();
}
SomeListener listener = new SomeListener() {
#Override
public void done() {
// do something
}
}
listener.done();
How can I do it with Protocol in Swift? Or can it actually be done?
That`s a way you can implement a protocol. Its like the delegate pattern in ObjC
protocol DoneProtocol {
func done()
}
class SomeClass {
var delegate:DoneProtocol?
func someFunction() {
let a = 5 + 3
delegate?.done()
}
}
class Listener : DoneProtocol {
let someClass = SomeClass()
init() {
someClass.delegate = self
someClass.someFunction()
}
// will be called after someFunction() is ready
func done() {
println("Done")
}
}
Related
How can we call class functions with a dynamic class name?
Assume the following example where I have two class with methods with same signature
class Foo{
class func doSomething()
}
class Foobar {
class func doSomething()
}
class ActualWork{
//call following method with a variable type so that it accepts dynamic class name
func callDynamicClassMethod(x: dynamicClass)
x.doSomething()
}
How can this be implemented so that x accepts values at run time
Edit: Sorry, I missed to mention that I was looking for any other ways other than protocol oriented approach. This is more of an exploratory question to explore if there is a more direct approach/pods/libraries to achieve this.
I liked this question, because it made me to think a lit'bit outside of the box.
I'll answer it, by dividing it into a few parts.
First
call class functions
Class function is basically a Type methods, which can be achieved using the static word inside the class context.
Taking that into account, you can get a simple solution, using protocol and passing the class reference (conforming to that protocol) like this:
protocol Aaa{
static func doSomething();
}
class Foo : Aaa{
static func doSomething() {
print("Foo doing something");
}
}
class FooBar : Aaa{
static func doSomething() {
print("FooBar doing something");
}
}
class ActualWork{
//Using class (static) method
func callDynamicClassMethod <T: Aaa> (x: T.Type) {
x.doSomething();
}
}
//This is how you can use it
func usage(){
let aw = ActualWork();
aw.callDynamicClassMethod(x: Foo.self);
aw.callDynamicClassMethod(x: Foo.self);
}
Second
In case you don't really need the method on the class context, you may consider using instance methods. In that case the solution would be even simpler, like this:
protocol Bbb{
func doSomething();
}
class Bar : Bbb{
func doSomething() {
print("Bar instance doing something");
}
}
class BarBar : Bbb{
func doSomething() {
print("BarBar instance doing something");
}
}
class ActualWork{
//Using instance (non-static) method
func callDynamicInstanceMethod <T: Bbb> (x: T){
x.doSomething();
}
}
//This is how you can use it
func usage(){
let aw = ActualWork();
aw.callDynamicInstanceMethod(x: Bar());
aw.callDynamicInstanceMethod(x: BarBar());
}
Third
If you need to use the class func syntax, as OP originally did:
class func doSomething()
You CANNOT simply use a protocol. Because protocol is not a class...
So compiler won't allow it.
But it's still possible, you can achieve that by using
Selector with NSObject.perform method
like this:
class ActualWork : NSObject{
func callDynamicClassMethod<T: NSObject>(x: T.Type, methodName: String){
x.perform(Selector(methodName));
}
}
class Ccc : NSObject{
#objc class func doSomething(){
print("Ccc class Doing something ");
}
}
class Ddd : NSObject{
#objc class func doSomething(){
print("Ccc class Doing something ");
}
#objc class func doOther(){
print("Ccc class Doing something ");
}
}
//This is how you can use it
func usage() {
let aw = ActualWork();
aw.callDynamicClassMethod(x: Ccc.self, methodName: "doSomething");
aw.callDynamicClassMethod(x: Ddd.self, methodName: "doSomething");
aw.callDynamicClassMethod(x: Ddd.self, methodName: "doOther");
}
Generics and Protocol oriented programming will do the job:
protocol Doable {
static func doSomething()
}
class Foo: Doable {
static func doSomething() {
debugPrint("Foo")
}
}
class Foobar: Doable {
static func doSomething() {
debugPrint("Foobar")
}
}
class ActualWork {
func callDynamicClassMethod<T: Doable>(x: T.Type) {
x.doSomething()
}
}
let work = ActualWork()
work.callDynamicClassMethod(x: Foo.self)
work.callDynamicClassMethod(x: Foobar.self)
you can achieve this with help of Protocol
protocol common {
static func doSomething()
}
class Foo : common{
static func doSomething() {
print("Foo")
}
}
class Foobar : common {
static func doSomething() {
print("Foobar")
}
}
class ActualWork{
//call following method with a variable type so that it accepts dynamic class name
func callDynamicClassMethod(x: common.Type) {
x.doSomething()
}
}
let fooObj : common = Foo()
let Foobarobj : common = Foobar()
let workObk = ActualWork()
workObk.callDynamicClassMethod(x:Foo.self)
workObk.callDynamicClassMethod(x:Foobar.self)
I think, there are three solutions. I shared an sample below.
Use "protocol" that has "doSomething()" function requirements.
Create a function which gets function definition as a parameter.
Use reflection. you can use EVReflection that is good Api for reflection.
sample code:
protocol FooProtocol {
static func doSomething()
}
class Foo: FooProtocol {
class func doSomething() {
print("Foo:doSomething")
}
}
class Foobar: FooProtocol {
class func doSomething() {
print("Foobar:doSomething")
}
}
class ActualWork {
func callDynamicClassMethod<T: FooProtocol>(x: T.Type) {
x.doSomething()
}
func callDynamicClassMethod(x: #autoclosure () -> Void) {
x()
}
func callDynamicClassMethod(x: () -> Void) {
x()
}
}
ActualWork().callDynamicClassMethod(x: Foo.self)
ActualWork().callDynamicClassMethod(x: Foobar.self)
print("\n")
ActualWork().callDynamicClassMethod(x: Foo.doSomething())
ActualWork().callDynamicClassMethod(x: Foobar.doSomething())
print("\n")
ActualWork().callDynamicClassMethod(x: Foo.doSomething)
ActualWork().callDynamicClassMethod(x: Foobar.doSomething)
Looks like you are searching for duck typing, and this is harder to achieve in a statically typed language (with some exceptions, listed in the linked Wikipedia page).
This is because dynamically calling a method requires knowledge about the layout of the target object, thus either inheritance of the class declaring the method, or conformance to a protocol that requires that method.
Starting with Swift 4.2, and the introduction of dynamic member lookup, there is another approach to solve your problem, however it also involves some ceremony:
// This needs to be used as base of all classes that you want to pass
// as arguments
#dynamicMemberLookup
class BaseDynamicClass {
subscript(dynamicMember member: String) -> () -> Void {
return { /* empty closure do nothing */ }
}
}
// subclasses can choose to respond to member queries any way they like
class Foo: BaseDynamicClass {
override subscript(dynamicMember member: String) -> () -> Void {
if member == "doSomething" { return doSomething }
return super[dynamicMember: member]
}
func doSomething() {
print("Dynamic from Foo")
}
}
class Bar: BaseDynamicClass {
override subscript(dynamicMember member: String) -> () -> Void {
if member == "doSomething" { return doSomething }
return super[dynamicMember: member]
}
func doSomething() {
print("Dynamic from Bar")
}
}
func test(receiver: BaseDynamicClass) {
receiver.doSomething()
}
test(receiver: Bar()) // Dynamic from Bar
To conclude, in the current Swift version there is no way to have both the argument and the method dynamic, some common ground needs to be set.
I'm trying to implement SharedInstanceDelegate in App class. I have no idea why the functions under the protocol are not being called.
This is my Protocol and class.
class App {
let sharedInstance = SharedInstance.shared
init() {
self.sharedInstance.delegate = self
}
}
extension App: SharedInstanceDelegate {
func1() { } // this is not executed
func2() { }
}
protocol SharedInstanceDelegate: class {
func1()
func2()
}
class SharedInstance {
static let shared = SharedInstance()
weak var delegate: SharedInstanceDelegate?
private init() { }
func method1() {
self.delegate?.func1() // this is executed
}
}
I believe you meant to make SharedInstanceDelegate a protocol, but you've made it a class. In either case, App does not conform/inherit SharedInstanceDelegate, so it's not clear how this would even compile.
Here is how I would implement your code to work with the delegate:
class App {
let sharedInstance = SharedInstance.shared
init() {
self.sharedInstance.delegate = self
}
}
extension App: SharedInstanceDelegate {
func func1() { } // this will run now
func func2() { }
}
protocol SharedInstanceDelegate {
func func1()
func func2()
}
class SharedInstance {
static let shared = SharedInstance()
var delegate: SharedInstanceDelegate?
private init() { }
func method1() {
self.delegate?.func1() // this is executed
}
}
Still no idea why this was happening, but cleaning the project fixed this. This is very strange. I have other delegates that call successfully.
Your code could work but it depends on how you are calling func1(). Calling it like this:
let testinstance = App().sharedInstance
testinstance.delegate?.func1()
will not work because you are not holding on to the App object. In this case the App object is the delegate, but because its a weak member and no one is retaining it, it gets released right away.
If you call it like this:
let testapp = App()
testapp.sharedInstance.delegate?.func1()
it works. In this case the App object is being retained and is still around when func1() is called.
Either way the way these classes are related is confusing to me. Why have a separate SharedInstance class at all?
I am wondering what the best practice is when I want some functions to be public and some to me internal when working with protocols.I am writing an AudioManager in Swift 3 wrapping AVPlayer as a framework. I want some methods to be public, so that e.g. a ViewController making use of the AudioManager can access some methods, but some methods would not be exposed outside the framework -> i.e. having the access modifier internal instead of public. I am writing the framework with protocol driven design, almost every part should have a protocol.So protocols are talking to protocols within the framework. E.g. the main class - AudioManager - has an AudioPlayer, and should be able to call some internal functions on it, e.g. pause(reason:) but that method should be internal and not exposed outside the framework.Here is an example.
internal enum PauseReason {
case byUser
case routeChange
}
// Compilation error: `Public protocol cannot refine an internal protocol`
public protocol AudioPlayerProtocol: InternalAudioPlayerProtocol {
func pause() // I want
}
internal protocol InternalAudioPlayerProtocol {
func pause(reason: PauseReason) // Should only be accessible within the framework
}
public class AudioPlayer: AudioPlayerProtocol {
public func pause() {
pause(reason: .byUser)
}
// This would probably not compile because it is inside a public class...
internal func pause(reason: PauseReason) { //I want this to be internal
// save reason and to stuff with it later on
}
}
public protocol AudioManagerProtocol {
var audioPlayer: AudioPlayerProtocol { get }
}
public class AudioManager: AudioManagerProtocol {
public let audioPlayer: AudioPlayerProtocol
init() {
audioPlayer = AudioPlayer()
NotificationCenter.default.addObserver(self, selector: #selector(handleRouteChange(_:)), name: NSNotification.Name.AVAudioSessionRouteChange, object: nil)
}
func handleRouteChange(_ notification: Notification) {
guard
let userInfo = notification.userInfo,
let reasonRaw = userInfo[AVAudioSessionRouteChangeReasonKey] as? NSNumber,
let reason = AVAudioSessionRouteChangeReason(rawValue: reasonRaw.uintValue)
else { print("what could not get route change") }
switch reason {
case .oldDeviceUnavailable:
pauseBecauseOfRouteChange()
default:
break
}
}
}
private extension AudioManager {
func pauseBecauseOfRouteChange() {
audioPlayer.pause(reason: .routeChange)
}
}
// Outside of Audio framework
class PlayerViewController: UIViewController {
fileprivate let audioManager: AudioManagerProtocol
#IBAction didPressPauseButton(_ sender: UIButton) {
// I want the `user of the Audio framwwork` (in this case a ViewController)
// to only be able to `see` `pause()` and not `pause(reason:)`
audioManager.audioPlayer.pause()
}
}
I know I can get it to work by changing the method pauseBecauseOfRouteChange to look like this:
func pauseBecauseOfRouteChange() {
guard let internalPlayer = audioPlayer as? InternalAudioPlayerProtocol else { return }
internalPlayer.pause(reason: .routeChange)
}
But I am wondering if there is a more elegant solution? Something like marking that the AudioPlayerProtocol refines the InternalAudioPlayerProtocol...
Or how do you fellow programmers do it?The framework is more beautiful if it does not expose methods and variables that are intended for internal use!
Thanks!
No, there is no more elegant solution to this, at least when considering protocols, and here is why:
Imagine a scenario that someone using your framework wants to write an extension for the AudioPlayerProtocol, how then pause(reason:) method can be implemented if it's internal?
You can achieve it by just subclassing and this code actually will compile:
public class AudioPlayer: AudioPlayerProtocol {
public func pause() {
pause(reason: .byUser)
}
internal func pause(reason: PauseReason) {
}
}
With protocols this is not the case, because you simply cannot guarantee implementation of internal function if someone with public access level wants to use your mixed public/internal protocol.
How about if you split your protocol into internal and public and then let the public implementation class delegate to an internal implementation. Like so
internal protocol InternalAudioPlayerProtocol {
func pause(reason: PauseReason)
}
public protocol AudioPlayerProtocol {
func pause()
}
internal class InternalAudioPlayer: InternalAudioPlayerProtocol {
internal func pause(reason: PauseReason) {
}
}
public class AudioPlayer: AudioPlayerProtocol {
internal var base: InternalAudioPlayerProtocol
internal init(base: InternalAudioPlayerProtocol) {
self.base = base
}
public func pause() {
base.pause(reason: .byUser)
}
}
public protocol AudioManagerProtocol {
var audioPlayer: AudioPlayerProtocol { get }
}
public class AudioManager: AudioManagerProtocol {
internal let base = InternalAudioPlayer()
public let audioPlayer: AudioPlayerProtocol
public init() {
audioPlayer = AudioPlayer(base: base)
}
internal func handleSomeNotification() {
pauseBecauseOfRouteChange() //amongst other things
}
internal func pauseBecauseOfRouteChange() {
base.pause(reason: .routeChange)
}
}
It's an old topic but what one can do is actually the opposite.
Instead of publicProtocol extending internalProtocol have internalProtocol extending publicProtocol.
public protocol AudioPlayerProtocol {
func pause() // I want
}
internal protocol InternalAudioPlayerProtocol: AudioPlayerProtocol {
func pause(reason: PauseReason) // Should only be accessible within the framework
}
public class AudioPlayer: InternalAudioPlayerProtocol {
public func pause() {
pause(reason: .byUser)
}
internal func pause(reason: PauseReason) {
//Do stuff
}
}
Then in the manager
public class AudioManager: AudioManagerProtocol {
public let audioPlayer: AudioPlayerProtocol
private let intAudioPlayer: InternalAudioPlayerProtocol
init() {
intAudioPlayer = AudioPlayer()
audioPlayer = intAudioPlayer
...
}
...
private func pauseBecauseOfRouteChange() {
intAudioPlayer.pause(reason: .routeChange)
}
}
I got a struct :
struct ErrorResultType: ErrorType {
var description: String
var code: Int
}
and a protocol:
protocol XProtocol {
func dealError(error: ErrorResultType)
}
Now I want to make an extention of UIViewController:
extension UIViewController: XProtocol {
func dealError(error: ErrorResultType) {
// do something
}
}
So I can subclass from this and override the function like:
class ABCViewController: UIViewController {
--->override func dealError(error: ErrorResultType) {
super.dealError(error)
// do something custom
}
}
But it goes wrong with: Declarations from extensions cannot be overridden yet
It doesn't make any sense to me. When I replace all ErrorResultType with AnyObject, the error won't appear any more.
Anything I missed?
For now the method in the extension must be marked with #objc to allow overriding it in subclasses.
extension UIViewController: XProtocol {
#objc
func dealError(error: ErrorResultType) {
// do something
}
}
But that requires all types in the method signature to be Objective-C compatible which your ErrorResultType is not.
Making your ErrorResultType a class instead of a struct should work though.
If i am not making mistake this is connected with Swift official extension mechanism for adding methods to classes.
Conclusion :
At the moment, it's not possible to override entities declared in
extension by subclassing, like so:
class Base { }
extension Base {
var foo: String { return "foo" }
}
class Sub: Base {
override var foo: String { return "FOO" } // This is an error
}
Please check this resource for more information : https://github.com/ksm/SwiftInFlux/blob/master/README.md#overriding-declarations-from-extensions
I have an extension on UIView implementing a protocol
protocol SomeProtocol {
var property : Int
}
extension UIView : SomeProtocol {
var property : Int {
get {
return 0
}
set {
// do nothing
}
}
}
in a concrete subclass I want to override this extension method:
class Subclass : UIView, SomeProtocol {
var _property : Int = 1
var property : Int {
get { return _property}
set(val) {_property = val}
}
}
I set breakpoints and see that the extension method is called and not the concrete subclass method:
var subclassObject = Subclass()
someObject.doSomethingWithConcreteSubclassObject(subclassObject)
// other code;
fun doSomethingWithConcreteSuclassObject(object : UIView) {
var value = object.property // always goes to extension class get/set
}
As others have noted, Swift does not (yet) allow you to override a method declared in a class extension. However, I'm not sure whether you'll ever get the behavior you want even if/when Swift someday allows you to override these methods.
Consider how Swift deals with protocols and protocol extensions. Given a protocol to print some metasyntactic variable names:
protocol Metasyntactic {
func foo() -> String
func bar() -> String
}
An extension to provide default implementations:
extension Metasyntactic {
func foo() -> String {
return "foo"
}
func bar() -> String {
return "bar"
}
}
And a class that conforms to the protocol:
class FooBar : Metasyntactic {
func foo() -> String {
return "FOO"
}
func bar() -> String {
return "BAR"
}
}
Swift will use dynamic dispatch to call the appropriate implementations of foo() and bar() based on each variable's runtime type rather than on the type inferred by the compiler:
let a = FooBar()
a.foo() // Prints "FOO"
a.bar() // Prints "BAR"
let b: Metasyntactic = FooBar()
b.foo() // Prints "FOO"
b.bar() // Prints "BAR"
If, however, we extend the protocol further to add a new method:
extension Metasyntactic {
func baz() -> String {
return "baz"
}
}
And if we override our new method in a class that conforms to the protocol:
class FooBarBaz : Metasyntactic {
func foo() -> String {
return "FOO"
}
func bar() -> String {
return "BAR"
}
func baz() -> String {
return "BAZ"
}
}
Swift will now use static dispatch to call the appropriate implementation of baz() based on the type inferred by the compiler:
let a = FooBarBaz()
a.baz() // Prints "BAZ"
let b: Metasyntactic = FooBarBaz()
b.baz() // Prints "baz"
Alexandros Salazar has a fantastic blog post explaining this behavior in depth, but suffice it to say that Swift only uses dynamic dispatch for methods declared in the original protocol, not for methods declared in protocol extensions. I imagine the same would be true of class extensions, as well.
I know this question has been asked a while ago. But this will be handy for someone who looking for an easier way. There is a way of overriding an extension methods. I know its bit hacky but it does the job beautifully.
If you declare your protocol with #objc
#objc protocol MethodOverridable {
func overrideMe()
}
In Extension
extension MainClass: MethodOverridable {
func overrideMe() {
print("Something useful")
}
}
Subclass - You can able to override it in your subclass. It works like a magic. Well, not really when adding #objc it exposes your protocol to Objective-C and its Runtime. That allows your subclass to override.
class SubClass: MainClass {
override func overrideMe() {
print("Something more useful")
}
}
Swift 5
class Class
{
#objc dynamic func make() { print("make from class") }
}
class SubClass: Class {}
extension SubClass {
override func make() {
print("override")
}
}
It looks like you can override property for 2nd super class property. For example, you can access UIView property by making extension to the UILabel wanting to override frame property of UIView. This sample works for me in Xcode 6.3.2
extension UILabel {
override public var frame: CGRect {
didSet {
println("\(frame)")
}
}
}
You can't do this through normal means.
It's in Apple's docs that you can't override a method in an extension in a subclass.
Also, extensions can add new functionality to a type, but they cannot override existing functionality.
https://docs.swift.org/swift-book/LanguageGuide/Extensions.html
I think you forgot to override the superclass property in your subclass:
class Subclass : UIView {
var _property : Int = 1
override var property : Int {
get { return _property}
set(val) {_property = val}
}
}