Delegate or closure for multiple event in same object - ios

There is
var tableView: MyTableView?
tableView?.onGoToA = {
self.goToA()
}
tableView?.onGoToB = {
self.goToB()
}
tableView?.onGoToC = {
self.goToC()
}
are there better way for this case or better that just use delegate?

If you have limited possible cases, I would have single closure that takes a enum as an argument and will have a switch case to decide which method to trigger
If each event has a value associated with it you can exploit enums with associated values as well :)
Example:
enum EventType {
case toA
case toB
case toC
}
Declare your closure as
var routerBlock: ((EventType) -> ())? = nil
Finally have router block implemented as
tableView?.routerBlock = {[weak self] (eventType) in
switch eventType {
case .toA:
self?.gotoA()
case .toB:
self?.goToB()
case .toC:
self?.goToC()
}
}
You can use the similar approach with delegates as well. Rather than having 3 delegate methods you can have one method which takes EventType and have the same switch block to decide which method to trigger
Hope this helps

Related

Converting Swift enum to Class

I have the following code to implement animation models based on this answer:
public enum AnimationType {
public enum Kind<Value> {
case scalar(Value)
case keyframes([Keyframe<Value>])
}
case position(Kind<Float>)
case scale(Kind<Float>)
case rect(Kind<CGRect>)
case transform(Kind<CGAffineTransform>)
....
....
}
public class Keyframe<T> : Codable, Comparable where T:Codable, T:Interpolatable {
public var time:CMTime
public var property:String
public var value:T
...
...
}
This data model was chosen as I found it type safe for each animation property as it couples data type with the property (for instance, value for property transform can only be CGAffineTransform, the code wouldn't accept anything else). But now I face two troubles:
Directly fetching property value or modifying keyframes is not so easy, one needs to write a big switch statement everytime or atleast if case let statement to fetch the property, which makes code look messy if done at hundreds of places,
Most important, Swift enums are pass by value but I realize I need pass by reference or class based implementation. This is because it would be much easier to modify the underlying object parameters in case of pass by reference. In case of pass by value such as enum, I need to again create new values and pass them to the animation code (which has it's own data model for rendering animation). Reconstructing or updating data structures for animation rendering is a pain and can be avoided with class.
However, I am not sure if there is such a type safe approach to convert such an enum to class, or make enum pass by reference for that matter. Any inputs are welcome.
If you want to keep using enums I think you can make issue 1 a bit easier to deal with if you add an optional property for each associated value in the enum cases.
Something like:
public enum AnimationType {
public enum Kind<Value> {
case scalar(Value)
case keyframes([Keyframe<Value>])
var scalar: Value? {
guard case let .scalar(value) = self else { return nil }
return value
}
var keyframes: [Keyframe<Value>]? {
guard case let .keyframes(keyframes) = self else { return nil }
return keyframes
}
}
case position(Kind<Float>)
case scale(Kind<Float>)
case rect(Kind<CGRect>)
case transform(Kind<CGAffineTransform>)
var position: Kind<Float>? {
guard case let .position(kind) = self else { return nil }
return kind
}
var transform: Kind<CGAffineTransform>? {
guard case let .transform(kind) = self else { return nil }
return kind
}
}
With this you won't need to have the big switch you are mentioning because you directly try to get the associated value you need.
You can also have a look at swift-case-paths which basically adds Keypath support to enum with associated values and removes the need to add this vars boilerplate.

Optional cast to protocol's associated type is failing (returning nil)

I have a protocol in my open source library (link in-case code samples aren't enough).
Said protocol has two associated types, one for a function "send" type, and one for a "return type" defined like so:
/// A protocol which can be adopted to define a function that can be performed on any given camera
public protocol CameraFunction {
/// An associated type which is taken as an input when calling this function on a `Camera` instance
associatedtype SendType
/// An associated type which is returned from the camera when calling this function on the `Camera`
associatedtype ReturnType
/// The enum representation of this given function
var function: _CameraFunction { get }
}
In a function implementation (performFunction declared on another protocol):
func performFunction<T>(_ function: T, payload: T.SendType?, callback: #escaping ((Error?, T.ReturnType?) -> Void)) where T : CameraFunction {
switch function.function {
case .getEvent:
let packet = Packet.commandRequestPacket(code: .getAllDevicePropData, arguments: [0], transactionId: ptpIPClient?.getNextTransactionId() ?? 0)
ptpIPClient?.awaitDataFor(transactionId: packet.transactionId, callback: { (dataResult) in
switch dataResult {
case .success(let data):
guard let numberOfProperties = data.data[qWord: 0] else { return }
var offset: UInt = UInt(MemoryLayout<QWord>.size)
var properties: [PTPDeviceProperty] = []
for _ in 0..<numberOfProperties {
guard let property = data.data.getDeviceProperty(at: offset) else { break }
properties.append(property)
offset += property.length
}
let event = CameraEvent(sonyDeviceProperties: properties)
callback(nil, event as? T.ReturnType)
case .failure(let error):
callback(error, nil)
}
})
ptpIPClient?.sendCommandRequestPacket(packet, callback: nil)
I create a CameraEvent object and attempt to downcast (unsure if that's the correct terminology) to T.ReturnType. At the point that is called, event is non-nil, however casting it to T.ReturnType gives a nil result even though it should match!
Event.get (.getEvent) is defined like so:
/// Functions for interacting with the event API on the camera
public struct Event: CameraFunction {
public var function: _CameraFunction
public typealias SendType = Bool
public typealias ReturnType = CameraEvent
/// Gets the current event
public static let get = Event(function: .getEvent)
}
It's important to note as well that another implementation of the second protocol I talk about (The one defining the performFunction function) successfully does very similar logic and I don't get nil back! There must be something I'm doing wrong here, but I have no idea what it could be!
Screenshots in case that helps!
Calling the protocol's function
Implementation of the protocol's function
This was... just the debugger being a pile of rubbish! Decided to add in a print statement to make absolutely sure it was nil. Turns out that wasn't the case! Prints fine, but lldb seems to think it's nil for whatever reason.

Use of function types or closures to dynamically call a function

I did some research but I could not solve my problem. Maybe due to my bad Swift know how :(
I do have a switch case. In each case I do the same things but call a different function. Is there a good way to move the duplicate logic outside the switch case and just set the needed function in the case block? The parameters of each function are also the same.
Here is an example code:
switch index {
case 0:
//do some stuff
myFuncCase_1(onCompletion: {
//do some async stuff
})
//do some more stuff
case 1:
//do some same stuff
myFuncCase_2(onCompletion: {
//do some same async stuff
})
//do some more same stuff
default: break
}
So, the only difference is the name of the function I will call.
Is there a good solution with closures or function types?
You can use a nested function to achieve this.
typealias Callback = (() -> Void)!
func someFunc() {
func switchExecution(_ function: ((_ completion: Callback) -> Void)!) {
//do some stuff
function {
//do async stuff
}
//do some more stuff
}
switch index {
case 0:
switchExecution(myFuncCase_1)
case 1:
switchExecution(myFuncCase_2)
default: break
}
}
Suppose you have some functions defined somewhere, with identical signatures.
func somefunc(callback:()->()) -> () {
// work, work, work
callback()
}
func otherfunc(callback:()->()) -> () {
// work, work, work
callback()
}
These functions have the type (()->())->()
This is a closure that takes one parameter and returns Void. The type of the one parameter is a closure that takes nothing and returns Void.
Note the parameter label (i.e, callback) is not part of the type.
Then you could do something like this:
var myfunc: (()->())->()
switch index {
case 0:
myfunc = somefunc
case 1:
myfunc = otherfunc
default:
myfunc = { _ in }
}
// do some same stuff
myfunc() {
// do some same async stuff
}
// do some more same stuff
The default case just creates an anonymous closure that doesn't do anything. You can't simply break on the default case because myfunc would be uninitialized upon use.

How to return closure in the generic

Now I using Realm to create a singleton, but I faced a problem, if I want to return a closure in the generic, and there are different types (Ex:.Case type return [Case], .Product type return [Product]), but I have no idea to implement this fuction.
Could anyone help me with this problem?Thanks!
DataType:
enum DataType{
case Case
case Product
case Category
case Composition
}
fetchItem fuction:
func fetchItem<T>(type: DataType,complete:#escaping ([T]) -> ()) {
var list:[T]? = []
switch type {
case .Case:
let realm = try! Realm()
let caseResult = realm.objects(Case.self)
caseResult.forEach { (item) in
...
}
complete([])
return
case .Product:
return
case .Category:
return
case .Composition:
return
}
}
Templating a function is the class that you want to get.
Let's take for exemple this function
func showTemplate<T>(myVariable: T) {
print(myVariable)
}
Here, if I want to call the showTemplate function I must do it with the type I want :
showTemplate<String>() # print a string
showTemplate<Int>() # print a int
showTemplate<myClass> # print a myClass
So you are having a problem, but in the wrong way because with templating, you HAVE to know the class before you call the function.
You can for example try to use inheritance and templating your motherClass with your wanted class.
class wantedClass {
var myCaseVariable: Case
var myProductVariable: Product
var myThingsVariable: Things
init() {
}
fillClass<T: Case>() {
// set case
}
// Etc etc
}
Moreover, I don't think that templating is the good solution here, I suggest to look at this : Using a Type Variable in a Generic
I believe you cannot do this for completely different types in one place using only generic type (not any class-holders or so). Maybe you should create separate funcs for each item (fetchCaseItems(), fetchProductItems, etc.). It's much clear to read and every func is responsible only for its own data type.

Swift enum function for only a single case of the enum?

I want to declare a function which I can only use for a single specific enum case.
For example I have CustomTextFieldTypes enum. This has the following cases and functions.
enum CustomTextFieldTypes {
case CardType
case CardNumber
case CardExpiryDate
case CardName
case CCVNumber
func inputCardNumber(cardNumber: String!, cardNumberTextField: XCUIElement?) {
cardNumberTextField?.typeText(cardNumber)
}
func inputCardCCVNumber(cardCCVNumber: String!, cardCCVNumberTextField: XCUIElement?) {
cardCCVNumberTextField?.typeText(cardCCVNumber)
}
}
Now I want to call the inputCardNumber(...) function only for the CustomTextFieldTypes.CardNumber case. I can do the following...
CustomTextFieldTypes.CardNumber.inputCardNumber(...)
But at the same time I can do this...
CustomTextFieldTypes.CardExpiryDate.inputCardNumber(...) or
CustomTextFieldTypes.CardNumber.inputCardNumber(...)
I only want to call the inputCardNumber(...) function for the CardNumber case. Not from another case the enum itself. How do I achieve this?
Thanks in advance for any help
EDIT- Here's some background on what I'm doing. I was writing a UI test which would input text into text fields. I wanted to keep the input code away from my test file and I started "Experimenting" with enums and enum functions. I was wondering if I could have a function explicitly available for an enum case. Judging from the comments I cannot do this (I checked online but didn't get far). It's not a bad architecture or anything, I was just splitting up test code..
Thanks for everyone for replying.
You can perform a switch on self in order to execute certain code for certain cases. Here's an example:
enum CustomTextFieldTypes {
case cardType
case cardNumber
case cardExpiryDate
case cardName
case ccvNumber
func inputCardNumber(cardNumber: String!, cardNumberTextField: XCUIElement?) {
switch self {
case .cardNumber:
cardNumberTextField?.typeText(cardNumber)
default:
return
}
}
}
No need to use a switch when you only want to match a single case:
enum CustomTextFieldTypes {
case cardType
case cardNumber
case cardExpiryDate
case cardName
case ccvNumber
func inputCardNumber(cardNumber: String!, cardNumberTextField: XCUIElement?) {
if case .cardNumber = self {
cardNumberTextField?.typeText(cardNumber)
}
}
}
Dont know exactly why are XCUIElements needed but do something like this
//MARK: Declaration
enum CustomTextFieldTypes {
case CardType(String)
case CardNumber(String)
case CardExpiryDate(String)
case CardName(String)
case CCVNumber(String)
}
//MARK: Definition
var cardNumber = CustomTextFieldTypes.CardNumber("123")
var cardExpiry = CustomTextFieldTypes.CardExpiryDate("10-10-2016")
//MARK: Usage
func useCard(type: CustomTextFieldTypes)
{
switch type {
case .CardNumber(let numberString):
print(numberString)
case .CardType(let cardtype):
print(cardtype)
case .CardExpiryDate(let expiryDate):
print(expiryDate)
case .CardName(let name):
print(name)
case .CCVNumber(let ccvnumber):
print(ccvnumber)
}
}
useCard(cardNumber)
useCard(cardExpiry)
If you really neeed XCUIElement then change case CardType(String) to case CardType(String, XCUIElement) and update all the other code as well

Resources