Delegate a structure in swift? - ios

I am developing an app to increase a little more my knowledge about swift. One of my questions if is it possible to delegate a optional function with a structure as an argument.
What yes Im able to do:
#objc protocol someProtocol {
optional func optionalFunc(someClass: someClass)
}
class someClass: NSObject {
}
But, what I want to do (problems representing a structure in objc):
#objc protocol someProtocol {
optional func optionalFunc(someStructure: someStructure)
}
struct someStructure {
}
And Im not able to find the way to solve this problem.
And the other thing I want, is similar to this but with enums instead of structs:
#objc protocol someProtocol {
optional func optionalFunc(someEnum: someEnum)
}
enum someEnum {
case example
}
If somebody can help me, I will be very grateful!
Lot of thanks! Luciano!

Swift 2.0 lets you do default implementations of protocols.
protocol someProtocol {
func optionalFunc(someStructure: SomeStructure)
}
extension someProtocol {
func optionalFunc(someStructure: SomeStructure){
// optional, leave empty
}
}
struct SomeStructure {
}
This way you can get around using the optional-decoration and do what you wanted.

You cannot pass the parameters as struct or enum, because it's only valid on Swift language, so it cannot be represented in Objective-C.
Another approach, you can declare a function as variable instead of func:
protocol someProtocol {
var optionalFunc: (someStructure) -> ()? { get set}
}
Implementation:
class someClass : someProtocol {
var optionalFunc: (someStructure) -> ()? = { yourStruct in
// Do anything with yourStruct
return
}
}
Using:
var someVar:someClass = someClass()
var result = someVar.optionalFunc(someStructure())
The result is a ()?. If you do not implement the variable, result will nil

Related

Extend a Protocol with Multiple Constraints for One OR the Other - Swift

I want to extend protocol with a default implementation that satisfies OR ( || ) constraint.
class A { }
class B { }
protocol SomeProtocol { }
/// It will throw error for ||
extension SomeProtocol where Self: A || Self: B {
}
You can't extend a protocol with OR as you can't do it in a if let, because with this the compiler infers the type of self or of the var, so if it conforms 2 types, the compiler doesn't know of what type is self.
(When you type self. or any var. the compiler always knows what type of var is in compiler type, in that case it would be in runtime). So the easiest way is to make that the 2 types conforms a protocol and do a extension of that protocol. So the compiler knows that self conforms a protocol and he doesn't care of the exact type of Self (But you will be able to use only the properties declared in the protocol).
protocol ABType {
// Properties that you want to use in your extension.
}
class A: ABType, SomeProtocol { }
class B: ABType, SomeProtocol { }
protocol SomeProtocol { }
extension SomeProtocol where Self: ABType {
}
Also if you want to apply the extension to both types you have to do it one by one.
extension A: SomeProtocol { }
extension B: SomeProtocol { }
// Silly example:
(In this case is not really useful, but it is just to show how to make to make 2 classes conforms a protocol and to make a extension of it using a method declared in that protocol and creating a default implementation.)
protocol ABType {
func getName()
}
class AClass: ABType {
func getName() {
print ("A Class")
}
}
class BClass: ABType, someProtocol {
func getName() {
print ("B Class")
}
}
protocol someProtocol {
func anotherFunc()
}
extension someProtocol where Self: ABType {
func anotherFunc() {
self.getName()
}
}
let a = AClass()
// a.anotherFunc() <- Error, A cant call anotherFunc
let b = BClass()
b.anotherFunc()

Override function error in swift

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

Swift - How can I override an extension method in a concrete subclass

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}
}
}

How to declare a function with a concrete return type conforming to a protocol?

EDIT:
This question was written before swift added the some keyword, making it obsolete
In objective-c I could declare a method with a return type:
-(UIView<MyProtocol> *)someMethod;
In this example the method returns a UIView that conforms to a protocol MyProtocol.
I want to do something like that in swift:
protocol MyProtocol {
var someProperty : Int {get set}
}
protocol MyDelegate {
func someMethod() -> UIView : MyProtocol // the view should conform to the protocol - I don't care what kind of view it is - I don't want to define a specific type of view
}
In general - The delegate should return a UIView with the var "someProperty"
I don't want to define a concrete UIView class.
I want the user to be able to return any type of UIView (As long as it conforms to the protocol)
The syntax I wrote is invalid - How should I be writing it?
You could just use the protocol as type:
protocol MyDelegate {
func someMethod() -> MyProtocol
}
And use it like this:
protocol MyProtocol {
var someProperty : Int {get set}
}
class CustomView: UIView, MyProtocol {
var someProperty = 2
}
protocol MyDelegate {
func someMethod() -> MyProtocol
}
struct Delegate: MyDelegate {
func someMethod() -> MyProtocol {
return CustomView()
}
}
let delegate = Delegate()
let view = delegate.someMethod()
let property = view.someProperty // property = 2
This is not possible in Swift. Not everything possible in Obj-C has to be possible in Swift. When creating a type requirement you can only combine protocols using the protocol<..., ...> syntax but you can't combine a class and a protocol.
Technically, this should be good for your architecture. You can probably find a workaround but I would advice against it. There is a reason to avoid combining classes with protocols because the interfaces are much more difficult to handle. Most OOP languages don't have that syntax. Many commonly used languages don't even have a syntax to combine protocols.
protocol MyProtocol {
var someProperty : Int {get set}
}
protocol MyDelegate {
func someMethod<T: UIView & MyProtocol>() -> T // the view should conform to the protocol - I don't care what kind of view it is - I don't want to define a specific type of view
}
class MyDelegateTestView : UIView, MyProtocol {
var someProperty: Int = 10
}
class MyDelegateTestClass : MyDelegate {
func someMethod<T>() -> T where T : UIView, T : MyProtocol {
return MyDelegateTestView() as! T
}
}
The question was written before the days of swift-ui
The "some" keyword has solved it by allowing opaque types to be returned from functions
protocol MyDelegate {
func someMethod() -> some MyProtocol
}
Here below is a way.
func myMethod(string: String) -> MyClass:MyProtocol? {
}
You can use without optional type as MyClass: MyProtocol.

Implement delegate using generic protocol in Swift

I'm trying to create a delegate protocol that implements a function which passes an array of a generic type. I've tried several combinations but none of them seem to do the trick.
This is the most approximate thing i've reached to. This is the protocol:
protocol APIControllerProtocol {
typealias T
func didReceiveAPIResults(results: [T])
}
And this is the the delegator object:
class APIController<U:APIControllerProtocol> {
typealias ElementType = U
var delegate: ElementType?
init(delegate: ElementType){
self.delegate = delegate
}
func getAPIResults(){
// Perform some action before delegation
// "results" is an Array of dictionaries got from NSJSONSerialization
self.delegate?.didReceiveAPIResults(results.map{dict in Album(json:dict)})
}
}
However, the last line get this error: "Album is not convertible to U.T"
"Album" is the model object used to return the results.
What am i doing wrong?
EDIT:
Following Mike S advice, i've made the protocol method didReceiveAPIResults a generic function, and specified what T is in the delegate. However, when receiving and assigning the argument of type T to a property in the delegate, i get the error: "T is not identical to T"
class TestDelegate: APIControllerProtocol {
typealias T = Album
var albums:[T] = [T]()
func didReceiveAPIResults<T>(results: [T]) {
// ...
self.albums = results //ERROR: "T is not identical to T"
}
}
Your didReceiveAPIResults declaration in APIControllerProtocol needs to be a generic function so that the generic type T is passed along to it correctly.
protocol APIControllerProtocol {
typealias T
func didReceiveAPIResults<T>(results: [T])
}
Note: This means your delegate definition will need to define what T is:
class TestDelegate: APIControllerProtocol {
typealias T = Album
func didReceiveAPIResults<T>(results: [T]) {
// ...
}
}
Update: While the code above does get rid of the original error, it turns out that it acts more like a workaround and doesn't really address the root of the problem.
The real issue seems to be that the compiler is having trouble reconciling what U.T is with no ambiguity. That's actually easy enough to fix though, we just need to give it a more precise definition (note the where clause in the APIController definition):
protocol APIControllerProtocol {
typealias T
func didReceiveAPIResults(results: [T])
}
class APIController<U:APIControllerProtocol where U.T == Album> {
typealias ElementType = U
// ...
}
Note: I removed the <T> that I added to the function in the protocol previously; that's not needed anymore and will end up causing problems later.
With that, the TestDelegate class works as expected (you don't even need the typealias anymore):
class TestDelegate: APIControllerProtocol {
var albums: [Album]? = nil
func didReceiveAPIResults(results: [Album]) {
albums = results
}
}

Resources