Assign Function to other class variable - swift

Sorry for if this asked many times, I tried many solution none of the work for me. I am doing a very basic thing like this way.
class NotificationModel: NSObject {
var selector = (() -> Void).self
}
Other class.
class TestNotificationClass1 {
init() {
var model = NotificationModel.init()
model.selector = handleNotification //error is here
}
func handleNotification() -> Void {
print("handle function 1")
}
}
Error description: Cannot assign value of type '() -> Void' to type '(() -> Void).Type'

If you want selector to be able to hold any function with no parameters and no return value then change its declaration to:
var selector: (() -> Void)?
This also makes it optional. If you don't want it to be optional then you need to add an initializer to NotificationModel that takes the desired selector as a parameter as shown below:
class NotificationModel: NSObject {
var selector: (() -> Void)
init(selector: #escaping () -> Void) {
self.selector = selector
super.init()
}
}
class TestNotificationClass1 {
init() {
var model = NotificationModel(selector: handleNotification)
}
func handleNotification() -> Void {
print("handle function 1")
}
}

Related

Observer method in MVVM Design Pattern swift?

I have one question about the code you can see below.
class Bindable<T> {
var value: T? {
didSet {
observer?(value)
}
}
var observer: ((T?) -> ())?
func bind(observer: #escaping (T?) -> ()) {
self.observer = observer // there is the place ı can not understand
observer?(value)
}
}
Why we doing this self.observer = observer? I expect we should use observer = self.observer instead of self.observer = observer. The reason why I think just like that
that is I think
We have changed the value
self.observer will worked
When we called func bind() because of the parameter observer is going to be equal to self.observer everything needs to be work perfectly.
But, what am I missing?
self.observer = observer means you assign this function to the class property observer
The first self.observer is the observer you defined in var observer: ((T?) -> ())?
And the second observer is the one you passed through the function func bind(observer: #escaping (T?) -> ())
Give you another example you will understand better.
class Person {
var age: Int = 0
func setAge(age: Int) {
self.age = age
}
// to let you understand better
// if the param is `anotherAge`
// `self.` is not necessary
func setAge2(anotherAge: Int) {
age = anotherAge
}
}
The self.age = age here is nothing different from your self.observer = observer, all are assigned a value to a class property.
The only difference is that your observer is a function also.

Execute closure from another method in an extension Swift

I have a class that is a delegate to a custom modal view, therefore it has a method for when the modal has been dismissed. I am extending that class and in the extension I have a method that accepts a completion closure.
I can't write in the main implementation of the class or the modal's implementation - only the extension.
I want to execute the closure when the modal is dismissed, but I can't seem to figure it out on my own. Is it even possible?
Here is an example of what I want to do:
extension MyClass {
func method(completion: (Int) -> ()) {
// showing the modal
}
}
extension MyClass: ModalDelegate {
func modalDismissed() {
// here I want to execute the completion passed to method()
}
}
Assign the completion as a variable to a MyClass's property in method and call it in modalDismissed:
class MyClass {
var classCompletion: (() -> ())?
}
extension MyClass {
func method(completion: #escaping () -> ()) {
classCompletion = completion
}
}
extension MyClass: ModalDelegate {
func modalDismissed() {
classCompletion?()
}
}
Update: If you can't "write in the main implementation of the class", here's a method using static property. This is a hack and has many limitations but does the work. Otherwise without writing to the main implementation you can't do anything.
extension MyClass {
static var classCompletion: (() -> ())?
func method(completion: #escaping () -> ()) {
MyClass.classCompletion = completion
}
}
extension MyClass: ModalDelegate {
func modalDismissed() {
MyClass.classCompletion?()
}
}

Swift: self in initializer has type (T) -> () -> T

TL;DR:
How does an NSObject's self variable acquire the type (T) -> () -> T?
Remarks
I can see why the use of self this way is not legal. But I am trying to make sense of the second error message.
The Code
struct DummyStorer {
let dummy: Dummy
}
struct Dummy {
let storer = DummyStorer(dummy: self)
// Use of unresolved identifier 'self'
// OK, that's reasonable. But...
}
class Dummy : NSObject {
let storer = DummyStorer(dummy: self)
// Cannot convert value of type '(Dummy) -> () -> Dummy' to expected argument type 'Dummy'
// ... how does the compiler arrive at this?
}
It is part of NSObjectProtocol
public protocol NSObjectProtocol {
func isEqual(_ object: Any?) -> Bool
var hash: Int { get }
var superclass: AnyClass? { get }
func `self`() -> Self // << here !!

swift: Assign function type to variable

struct System {
var method: (() -> ())?
var curMethod: Int
init() {
method = nil
curMethod = 0
}
mutating func method1() {
curMethod = 1
}
mutating func method2() {
curMethod = 2
}
}
var sys = System()
sys.method = System.method1
sys.method!()
I get an error cannot assign value of type (inout System) -> () -> ()' to type '(() -> ())?. What am I doing wrong?
First of all, your line sys.method = System.method1 is wrong, as it would require method1 to be a static function (like a class function) rather than an instance function, so it should be changed to sys.method = sys.method1. But this isn't allowed - the error is "error: partial application of 'mutating' method is not allowed".
If you make System a class (rather than a struct), it will work if you replace the System.method1 with sys.method1.
The reason for this is that a mutating func is actually quite a lot more than a simple function under the hood - it is a curried function (curried with a compiler generated function) that effectively creates a new copy of the struct with the "new" value - hence, you A) can't access it it directly ("partial application is not allowed") and B) you can't assign it to a ()->() variable.
So, there're 3 variants suggested by participants. Everything is working, and using class instead of struct seems to me less complicated.
struct System1 {
var method: (() -> ())?
var curMethod: Int
init() {
method = nil
curMethod = 0
}
mutating func method1() { curMethod = 1 }
mutating func method2() { curMethod = 2 }
}
struct System2 {
var method: ((inout System2) -> ())?
var curMethod: Int
init() {
method = nil
curMethod = 0
}
mutating func callCurrentMethod() { method?(&self) }
mutating func method1() { curMethod = 1 }
mutating func method2() { curMethod = 2 }
}
class System3 {
var method: (() -> ())?
var curMethod: Int
init() {
method = nil
curMethod = 0
}
func method1() { curMethod = 1 }
func method2() { curMethod = 2 }
}
var struct1 = System1()
var struct2 = System2()
var class1 = System3()
print(struct1.curMethod)
let curried = System1.method1
let unsafe = curried(&struct1)
unsafe()
print(struct1.curMethod)
print(struct2.curMethod)
struct2.method = { $0.method1() }
struct2.callCurrentMethod()
print(struct2.curMethod)
print(class1.curMethod)
class1.method = class1.method1
class1.method!()
print(class1.curMethod)

Mock third party classes (Firebase) in Swift

I'm trying to unit test a class of my own which is calling a method on a third party class:
FIRAuth.auth()?.signInAnonymously() { (user, error) in
//
}
I'm using protocol based dependency injection to achieve this:
protocol FIRAuthProtocol {
func signInAnonymously(completion: FIRAuthResultCallback?)
}
extension FIRAuth: FIRAuthProtocol {}
class MyClass {
private var firAuth: FIRAuthProtocol
init(firAuth: FIRAuthProtocol) {
self.firAuth = firAuth
}
func signIn() {
firAuth.signInAnonymously() { (user, error) in
//
}
}
}
class MockFIRAuth: FIRAuthProtocol {
var signInAnonymouslyCalled = false
func signInAnonymously(completion: FIRAuthResultCallback? = nil) {
signInAnonymouslyCalled = true
}
}
class MyClassSpec: QuickSpec {
override func spec() {
describe("MyClass") {
describe(".signIn()") {
it("should call signInAnonymously() on firAuth") {
let mockFIRAuth = MockFIRAuth()
let myClass = MyClass(firAuth: mockFIRAuth)
expect(mockFIRAuth.signInAnonymouslyCalled).to(beFalse())
myClass.signIn()
expect(mockFIRAuth.signInAnonymouslyCalled).to(beTrue())
}
}
}
}
}
So far so good!
Now, I'd like my mockFIRAuth to return an instance of FIRUser.
Here's my issue: I can't create an instance of FIRUser myself.
FYI: public typealias FIRAuthResultCallback = (FIRUser?, Error?) -> Swift.Void
If found this great article which explains how to make a method on a third party class return a protocol instead of a type. http://masilotti.com/testing-nsurlsession-input/
Maybe my situation is different than the article's, but here's my shot at this:
I've defined a FIRUserProtocol:
protocol FIRUserProtocol {
var uid: String { get }
}
extension FIRUser: FIRUserProtocol {}
I've updated my FIRAuthProtocol to call the completion handler with FIRUserProtocol instead of FIRUser:
protocol FIRAuthProtocol {
func signInAnonymously(completion: ((FIRUserProtocol?, Error?) -> Void)?)
}
I've updated my FIRAuth extension to support the modified protocol. My newly defined method calls the default implementation of signInAnonymously:
extension FIRAuth: FIRAuthProtocol {
func signInAnonymously(completion: ((FIRUserProtocol?, Error?) -> Void)? = nil) {
signInAnonymously(completion: completion)
}
}
Finally, I've updated MockFIRAuth to support the modified protocol:
class MockFIRAuth: FIRAuthProtocol {
var signInAnonymouslyCalled = false
func signInAnonymously(completion: ((FIRUserProtocol?, Error?) -> Void)? = nil) {
signInAnonymouslyCalled = true
}
}
Now, when I run my test everything comes to a crashing halt:
Thread 1: EXC_BAD_ACCESS (code=2, address=0x7fff586a2ff8)
Please advice!
Update
After renaming the completion argument label in my FIRAuthProtocol's method everything seems to work as expected:
protocol FIRAuthProtocol {
func signInAnonymously(completionWithProtocol: ((FIRUserProtocol?, Error?) -> Void)?)
}
extension FIRAuth: FIRAuthProtocol {
func signInAnonymously(completionWithProtocol: ((FIRUserProtocol?, Error?) -> Void)? = nil) {
signInAnonymously(completion: completionWithProtocol)
}
}
This solves my issue for now, but I'd still like to know why my first attempt was unsuccessful. Does this mean that the two methods with different parameter types in their closures can't be told apart, which was causing my app to crash?
I've finally found an elegant way to solve this.
protocol FIRAuthProtocol {
func signInAnonymously(completion: ((FIRUserProtocol?, Error?) -> Void)?)
}
extension FIRAuth: FIRAuthProtocol {
func signInAnonymously(completion: ((FIRUserProtocol?, Error?) -> Void)? = nil) {
let completion = completion as FIRAuthResultCallback?
signInAnonymously(completion: completion)
}
}
This way, there's no need to alter function names or argument labels.