Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to pass expression as argument in a function in Swift?

Tags:

ios

swift

I am a junior iOS developer. I want to refactor my code. currently I want to refactor my realm methods. to save or delete data in Realm, I need to use a lot of do try catch block all over the place, so I want to make a service to handle this. I have tried but I don't know if this is the correct way or not

import RealmSwift

class RealmService {

    private init() {}
    static let shared = RealmService()

    var realm = try! Realm()

    func save(expression: ()) {

        do {
            try realm.write {

            // I want to pass the expression in this block here

                expression
            }
        } catch {
            post(error)
        }

    }


}

usage:

func saveToRealmDatabase(wishList: WishList, product: Product) {


    RealmService.shared.save(expression: {
        // I want to pass expression in the block in here as argument
        wishList.products.append(product)
    }())



}

I want to pass the expression wishList.products.append(product) as argument of the function in RealmService class. is there a better way to achieve that ?

like image 817
sarah Avatar asked Nov 28 '18 06:11

sarah


People also ask

How do you pass a function as an argument in Swift?

If a function takes another function as an argument in Swift, you do not need to specify a separate function and pass that as an argument. Instead, you can use a closure function. A closure is an anonymous function. It is a block of code that acts as a function but does not have a name.

Can we pass a function as an argument to a function?

We cannot pass the function as an argument to another function. But we can pass the reference of a function as a parameter by using a function pointer.

What is Inout in Swift?

Swift inout parameter is a parameter that can be changed inside the function where it's passed into. To accept inout parameters, use the inout keyword in front of an argument. To pass a variable as an inout parameter, use the & operator in front of the parameter.

What is #function Swift?

A function is a set of statements organized together to perform a specific task. A Swift 4 function can be as simple as a simple C function to as complex as an Objective C language function. It allows us to pass local and global parameter values inside the function calls.


2 Answers

Your "expression" can be represented by the type () -> Void - a closure that accepts no parameters and returns nothing.

This is how your method should be declared:

func save(expression: @escaping () -> Void) {

    do {
        try realm.write {
            expression()
        }
    } catch {
        post(error)
    }

}

This is how you should use it:

func saveToRealmDatabase(wishList: WishList, product: Product) {


    RealmService.shared.save(expression: {
        wishList.products.append(product)
    })
}
like image 103
Sweeper Avatar answered Oct 19 '22 03:10

Sweeper


From the approach you are trying i can guess you want to do something like,

RealmService.shared.save(expression: {
        wishList.products.append(product)
        realm.add(wishList.products)
    })

So based on the understanding that you want to perform the addition operation in that callback, i would rather suggest the below implementation where you don't need to implement the callback for every operation. Rather when you are interested to know the status of the operation then only you would implement the callback. Check the below snippet,

class RealmService {

    private init() {}
    static let shared = RealmService()

    var realm = try! Realm()

    /// Saving a list of object i.e, List<Object>
    func save<O, L: List<O>>(_ list: L, callback: ((Error?) -> Void)? = nil) where O: Object {
        do {
            try realm.write {
                realm.add(list)
                callback?(nil)
            }
        } catch {
            callback?(error)
        }
    }

    /// Saving a single object i.e, `Object`
    func save(_ object: Object, callback: ((Error?) -> Void)? = nil) {
        do {
            try realm.write {
                realm.add(object)
                callback?(nil)
            }
        } catch {
            callback?(error)
        }
    }
}

Usage

class Dog: Object {
   @objc dynamic var name = ""
   @objc dynamic var age = 0
}

let tomy = Dog()
tomy.name = "Tomy"

let johny = Dog()
johny.name = "Johny"

let dogs = List<Dog>()
dogs.append(tomy)
dogs.append(johny)

//When you are not interested in save operation status
RealmService.shared.save(dogs)

//When you want to handle error while saving
RealmService.shared.save(dogs) { [weak self] in self?.showAlert($0) } 

func showAlert(_ error: Error?) {
    guard let e = error else { return }
    showAlert(alertTitle: "Error", alertMessage: e.localizedDescription, actionTitle: "Back")
}
like image 34
Kamran Avatar answered Oct 19 '22 02:10

Kamran