Swift - how to implement protocol methods in function - swift

In android, it is possible to implement interface methods during function call. For example, the declaration of interface and function:
//interface
interface exampleCallback {
void success(String response);
void error(String error);
}
//function
void exampleFunction(exampleCallback cb) {
//do something
}
And the function call:
exampleFunction(new exampleCallback() {
#Override
public void success(String response) {
//custom method implementation
}
#Override
public void error(String error) {
//custom method implementation
}
});
That is, the success/error methods can be customized for each function call of the exampleFunction.
However, after some google search, I can only find example codes for implementing protocol methods in class or struct declaration, in which the methods can no longer be customized. I know I can pass escaping closure as function parameter to achieve the goal, i.e., customize callback function for each function call. But just wonder if I can use protocol to do the similar thing...

You can create an enumeration with associated values:
enum Result {
case success(String)
case error(CustomError)
}
enum CustomError: Error {
case expired(String)
}
And use the enumeration cases in a completion handler of your method to pass your custom string:
func exampleFunction(completion: #escaping (Result) -> ()) {
if condition {
completion(.success("Success String"))
} else {
completion(.error(.expired("Error String")))
}
}
When calling your method you can switch your enumeration and do your custom implementation there as well as use the associated value returned in your callback:
exampleFunction { result in
switch result {
case let .success(response):
// custom method implementation
// use your (response) string here
case let .error(error):
// custom method implementation
// use your (error.localizedDescription) string here
}
}
Playground Sample

Anonymous classes in Java is really just a "workaround" for the absence of functions as "first class citizens".
In swift, functions are first class citizens, so you don't actually need to pass an anonymous class that implements a single method. You just pass that method (somewhat similar to Java 8's lambdas).
This in Java:
interface ActionListener {
void actionPerformed();
}
Can just be represented by a closure type in Swift:
() -> Void
Instead of doing this:
someMethod(new ActionListener() {
public void actionPerformed() { ... }
});
You do this in Swift:
someMethod { ... }
What if your interface in Java has multiple methods to implement?
In that case, you can't use one single closure to represent them all. You need to either
create a protocol with multiple methods and implement it in a struct or class. You see this pattern a lot in UIKit. Views and view controllers often has a XXXDelegate.
pass a tuple of closures

Related

Flutter, Dart. Create anonymous class

Maybe it's really dumb question. But I cannot believe there is no resources, where it's described. Even from the official documentation. What I'm trying to do, it's create Anonymous class for the next function.
How to create Anonymous class in Dart with custom function something like next in Kotlin?
Handler(Looper.getMainLooper()).post(Runnable() {
#override
open fun run() {
//...
}
private fun local() {
//....
}
})
Dart does not support creating an anonymous class.
What you're trying to do is not possible.
On the other hand, you can create anonymous functions. So you could use that to mimic an anonymous class.
The idea is to add a constructor of your abstract class, that defer its implementation to callbacks.
abstract class Event {
void run();
}
class _AnonymousEvent implements Event {
_AnonymousEvent({void run()}): _run = run;
final void Function() _run;
#override
void run() => _run();
}
Event createAnonymousEvent() {
return _AnonymousEvent(
run: () => print('run'),
);
}
It's not strictly the same as an anonymous class and is closer to the decorator pattern. But it should cover most use-cases.
This is an alternative way, but not fully equivalent:
Problem, e.g.:
I would like to implement OnChildClickListener inline in my code without class. For this method:
void setOnChildClickListener(OnChildClickListener listener) {
...
}
Instead of this:
abstract class OnChildClickListener {
bool onChildClick(int groupPosition, int childPosition);
}
use this:
typedef OnChildClickListener = Function(int groupPosition, int childPosition);
And in code you can implement it in this way:
listView.setOnChildClickListener((int groupPosition, int childPosition) {
// your code here
});
In other words do not use abstract class, but use typedef.

RxAndroid: How to add additional methods in Observer and Observable

Observer has onNext(), OnError() and onComplete().
Is there a way to add an additional method?
There is a possibility that the object received via the stream is of two types instead of the same type. And both possibilities are a success scenario. They are just handled differently by the observer.
Now, with callbacks, one would add a new method to handle this.
But not sure how this would be done with Rx.
Or is there another way of handling this without having to add a new method?
Thanks
I think the best way to achieve this is by using a common super class which can hold both objects.
In Kotlin you can do this with sealed class in Java do it with a simple POJO. One downside is that you have to use instanceOf and casting to use the actual type.
public class Result<T> {
public T result;
public Result(T result) {
this.result = result;
}
}
public class Result1 extends Result<Object1> {
public Result1(Object1 result) {
super(result);
}
}
public class Result2 extends Result<Object2> {
public Result2(Object2 result) {
super(result);
}
}
Your Observable can emit Result objects, and you can cast to either result based on what you got on the onNext method.

In TypeScript, how to prevent a method from being called on derived class?

There are three classes.
// in external library, which I don't want to modify
class ComponentBase {
// I want calling this to be disallowed
forceUpdate() {}
}
class ComponentBase_MyVersion extends ComponentBase {
// I want subclasses to always call this, instead of forceUpdate()
Update() {}
}
class MyComponent extends ComponentBase_MyVersion {
DoSomething() {
// I want this to be disallowed
this.forceUpdate();
// forcing the subclass to call this instead
this.Update();
}
}
How can I accomplish this, with changes only to ComponentBase_MyVersion?
Is there a way to "hide" a base-class member?
Or perhaps a way to override the definition -- like with the "new" keyword in C# -- letting me mangle the method definition to at least make warnings appear when attempting to call it?
The OOP does not allow you to do this kind of method cancellation. You can impleement this funcion on your class with an Exception like you suggested, or use a composition: https://en.wikipedia.org/wiki/Composition_over_inheritance
Example 1:
class ComponentBase {
forceUpdate() {}
}
class ComponentBase_MyVersion extends ComponentBase {
Update() {}
forceUpdate() {
throw new Error("Do not call this. Call Update() instead.");
}
}
class MyComponent extends ComponentBase_MyVersion {
DoSomething() {
// wil raise an exception
this.forceUpdate();
this.Update();
}
}
Example 2 (composition):
class ComponentBase {
forceUpdate() {}
}
class ComponentBase_MyVersion {
private _component: ComponentBase = ...;
Update() {}
// expose _component desired members ...
}
class MyComponent extends ComponentBase_MyVersion {
DoSomething() {
// compilation error
this.forceUpdate();
this.Update();
}
}
I hope I helped.
Encapsulate implementation by replacing inheritance with composition Delegation Pattern
You can do this by adding the private access modifier on the forceUpdate method. This will result in all the subclasses being unable to access forceUpdate. However TypeScript does not support package access modifiers, but you can do this by replacing inheritance with composition.
class ComponentBase {
forceUpdate() {
}
}
class ComponentBase_MyVersion {
// Replace inheritance with composition.
private component: ComponentBase;
Update() {
this.component.forceUpdate();
}
}
class MyComponent extends ComponentBase_MyVersion {
DoSomething() {
// Now subclass can't access forceUpdate method
this.Update();
}
}
Use a symbol in order to prevent external access to the method.
If you don't want to replace inheritance with composition, you can use Symbol to define a method. If your target is es5 you must configure tsconfig.json compilerOptions.lib to include es2015.symbol. Because every symbol is unique, any external module will not be able to obtain the symbol and access the method.
// libs.ts
let forceUpdate = Symbol("forceUpdate");
export class ComponentBase {
[forceUpdate]() {
}
}
export default class ComponentBase_MyVersion extends ComponentBase {
Update() {
this[forceUpdate]();
}
}
// test.ts
import ComponentBase_MyVersion from "./libs";
class MyComponent extends ComponentBase_MyVersion {
DoSomething() {
// Now subclass can't access the forceUpdate method.
this.Update();
}
}
I found a way that seems to work -- that is, which causes warnings to appear when someone attempts to call forceUpdate() on a subclass instance.
forceUpdate(_: ()=>"Do not call this. Call Update() instead.") {
throw new Error("Do not call this. Call Update() instead.");
}
Now when I write new MyComponent().forceUpdate(), I get a compiler error, with the warning message containing a description telling me to use Update() instead.
EDIT: Apparently this only works because the base class already had this definition:
forceUpdate(callBack?: () => any): void;
If instead the base method is defined with no arguments originally (as in the OP), the above solution doesn't work.
However, if you have a case like mine (where there's an optional property like that, which you can narrow the return-type of), it works fine. (not sure if this return-type-narrowing is a bug, or intended)

How to execute once when module loads?

I need to create objects from string names that I am reading from a script. I don't want to use the Objective-C runtime.
In my C++ implementation, each class registered itself with an object factory singleton through a global static variable. When the dll loads, the globals were initialized, and all available classes were registered.
I don't want the object factory to have hard coded pre-knowledge of all possible types.
In Swift, all globals are lazily initialized so my C++ registration strategy doesn't work.
Is there some init API that swift calls once per module load?
If not, does anyone have a good idea for class registration?
public enum DynamicTypeFactoryError : ErrorType {
case ClassNotRegistered
}
public protocol DynamicType {
static var dynamicClassName: String { get }
init()
}
public struct DynamicTypeRegistraion<T: DynamicType> {
public init() {
DynamicTypeFactory.inst.register(T.dynamicClassName, factory: { T() })
}
}
//===========================================================================
// singleton
public class DynamicTypeFactory {
// properties
public static let inst = DynamicTypeFactory()
typealias ClassFactoryType = (Void) -> DynamicType
var registry = [String : ClassFactoryType]()
// methods
public func create(className: String) throws -> DynamicType {
// make sure the class exists
guard let factory = registry[className] else {
throw DynamicTypeFactoryError.ClassNotRegistered
}
return factory()
}
/// This is used to register an object so it can be dynamically created
/// from a string.
public func register(className: String, factory: (Void) -> DynamicType) {
if (registry[className]) != nil {
// TODO - this should be logged
assertionFailure("Class: \(className) is already registered")
} else {
registry[className] = factory
}
}
}
//===========================================================================
// MyObject
public struct MyObject : DynamicType {
// properties
static let registration = DynamicTypeRegistraion<MyObject>()
public static var dynamicClassName = "MyObject"
public init() {
}
}
// Usage
let myObj = try? DynamicTypeFactory.inst.create("MyObject")
Since MyObject's static registration is not initialized, calling create fails because it hasn't been registered yet.
After reviewing the links posted by Martin R, it appears there is no "non-lazy" initialization of statics, and this is by design. So a different approach will be needed for Swift applications. Thanks Martin!
There are two methods in Objective C which are used to load and initialize a class.
+load and +initialize
1. In swift you can use "public override class func initialize()" to put your initialization code, please note that it will be called lazily.
Support for overriding load was removed in Swift 1.2
Here is what docs say about initialize method
"The runtime sends initialize to each class in a program just before the class, or any class that inherits from it, is sent its first message from within the program. The runtime sends the initialize message to classes in a thread-safe manner. Superclasses receive this message before their subclasses."

Making Extension method Generic

In this post there's a very interesting way of updating UI threads using a static extension method.
public static void InvokeIfRequired(this Control c, Action<Control> action)
{
if(c.InvokeRequired)
{
c.Invoke(() => action(c));
}
else
{
action(c);
}
}
What I want to do, is to make a generic version, so I'm not constrained by a control. This would allow me to do the following for example (because I'm no longer constrained to just being a Control)
this.progressBar1.InvokeIfRequired(pb => pb.Value = e.Progress);
I've tried the following:
public static void InvokeIfRequired<T>(this T c, Action<T> action) where T : Control
{
if (c.InvokeRequired)
{
c.Invoke(() => action(c));
}
else
{
action(c);
}
}
But I get the following error that I'm not sure how to fix. Anyone any suggestions?
Error 5 Cannot convert lambda expression to type 'System.Delegate' because it is not a delegate type
replace :
c.Invoke(() => action(c));
with :
c.Invoke(action, c);
This is a well known error with lambdas and anonymous methods:
Convert this delegate to an anonymous method or lambda
Your code just needs a cast to compile:
public static void InvokeIfRequired<T>(this T c, Action<T> action) where T : Control
{
if (c.InvokeRequired)
{
c.Invoke((Action<T>)((control) => action(control)));
}
else
{
action(c);
}
}
Try this slight varient:
public static void InvokeIfRequired<T>(this T c, Action<T> action) where T : Control
{
if (c.InvokeRequired)
{
c.Invoke((Action<T>)(() => action(c)));
}
else
{
action(c);
}
}
You need to cast it as a Delegate type. Kinda stupid I know. I can't really give you a good reason why a lambda expression isn't implicitly assignable as a delegate.