Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access a custom function from any file in the same Swift project?

Tags:

swift

swift3

If the postfix operator of a custom function is declared at file scope - as in my previous post - there must be a way to access such a function from another Swift 3 file in the same Xcode project.

Apple’s documentation on custom functions states that “New operators are declared at a global level …“ so I can presume the creators of Swift 3 would consider it important for a custom function to be accessed globally. But for a novice in Swift it is not self-evident how I would do this.

Based on code in my previous accepted answer (here) what would I need to do so a custom function can be accessed from another file elsewhere in the project ?


FINAL EDIT

The solution is embarrassingly simple (see accepted answer) and hopefully other Swift novices may also find it useful.

A postfix operator % is declared globally while an Extension of Int reads an Int variable from another file. Extensions of Double and CGFloat as well as Int are also possible.

CustomOperators.swift

import UIKit

postfix operator %

extension Double {
    static postfix func % (n: Double) -> Double {
     return Double(n) /  100
    }
}

extension Int {
    static postfix func % (n: Int) -> Double {
        return Double(n) /  100
    }
}

extension CGFloat {
    static postfix func % (n: CGFloat) -> Double {
        return Double(n) /  100
    }
}

ViewController.swift

import UIKit

class ViewController: UIViewController {

    let test1: Double   = 93.7
    let test2: Int      = 80
    let test3: CGFloat  = 70

    override func viewDidLoad() {
        super.viewDidLoad()

    print(test1%)       // prints '0.937'
    print(test2%)       // prints '0.8'
    print(test3%)       // prints '0.7'

    }
}

Thanks marosoiae, and also Martin R and unniversal for your input.


EDIT 2

Martin R’s comments prompted me to try a further example with my custom postfix function defined in Utils but in file scope rather than as a static postfix function. Utils becomes an empty class for custom functions all defined in file scope outside the class.

import UIKit

class ViewController: UIViewController {

let value: Int  = 25

override func viewDidLoad() {
    super.viewDidLoad()

    example1()
    example2()
}


func example1() {

    // 1. call to a function in Utils with an explicit value 
    // and nothing returned from Utils. 
    // Note this uses literal postfix syntax i.e. 25%

    Utils.25%


    // Debug message:
    // Type 'Utils' has no member '25'

    }


func example2() {

    // 2. call to a function in Utils with an argument 
    // declared in UIViewController and nothing returned from Utils

    Utils.(Int: value)%

    // Debug message
    // Expected member name following '.'

    }
}

Utils.swift now compiles but from debug messages that Xcode reports with both examples, it is clear that the token '%' is expected immediately following the '.'.

Even without returning a variable from Utils.swift, this is obviously not how to call a postfix function in Utils.swift from a file elsewhere in the project. My question remains: how would I do it ?


EDIT 1

At this point it might help to include some code so I created a class with static functions, following the syntax (as far as possible) used in Unniversal's answer. I decided to try static functions if these help avoid cluttering the global scope with methods that should be owned by a class/struct.

File 1 - Utils

import UIKit

postfix operator %

class Utils {

    static func yourFunction(){
    //Do your stuff here
    }

    static func yourFunction1(value: Int) {
    print(value)
    }

    static postfix func % (percentage: Int) -> Double {
        return (Double(percentage) / 100)
    }    
}

The static function % reports

    Member operator '%' must have at least one argument of type 'Utils'

which I’d expect to disappear once an argument is supplied from another file.

The following code shows four ways I tried to supply an argument to static functions in Utils. I ran the project with one example at a time

File 2 - UIViewController

import UIKit

class ViewController: UIViewController {

    let value: Int  = 25
    var percentage  = Double()


    override func viewDidLoad() {
        super.viewDidLoad()
//        example1()
//        example2()
//        example3()
//        example4()
    }





func example1() {

    // 1. call to a function in Utils with no argument and no return (i.e. suggested answer)

    Utils.yourfunction()

    // Debug messages:
    // Type 'Utils' has no member 'yourfunction'
    // Did you mean 'yourFunction'?
    // Did you mean 'yourFunction1'?

    }


func example2() {

    // 2. call to a function in Utils with argument and no return

    Utils.yourfunction1(Int: Int)

    // Debug messages:
    // Type 'Utils' has no member 'yourfunction'
    // Did you mean 'yourFunction'?
    // Did you mean 'yourFunction1'?

    }

func example3() {

    // 3. call to a function in Utils with argument and returning a value for percentage

    Utils.%() {
        return Int(percentage)
    }

    // Debug message:
    // Use of unresolved operator '.%'

    }

func example4()  {

    // 4. call to a function in Utils with argument and returning a value for percentage

    percentage = Utils.%(Int: value) -> Int {
        return Int(percentage)
    }

    // Debug messages:
    // Use of unresolved operator '.%'
    // Expected type before '->'
    // Expected type after '->'

    }
}

As far as I can see, static functions Utils.yourFunction and Utils.yourFunction1 can’t be accessed from outside Utils, as shown in example 1 and 2. And the postfix operator % seems to cause Xcode to report Use of unresolved operator ‘.%’, as shown in example 3 and 4. However these problems might be the way I adapted the syntax used by Unniversal.

like image 963
Greg Avatar asked Dec 24 '22 23:12

Greg


2 Answers

Any function declared at file scope will have the implicit scope internal and will be visible in the rest of the project/module.

I recommend reading the access control guide for more information.

Edit:

I'm still not sure what you're trying to do, but it looks like you are mixing global functions with static methods and custom operators.

If what you want is to declare a custom operator that you can use in any other file in the project, the solution is in the documentation that you linked in your question.

So this is what you need to declare a custom % (as you defined it) for the Int type:

CustomOperators.swift

postfix operator %

extension Int {

    static postfix func % (n: Int) -> Double {
        return Double(n) / 100
    }

}

main.swift

print(90%) //outputs "0.9"

That's all there is to it. You simply declare the operator globally: postfix operator % and you define the operator function as a static method in a extension on the Int type.

Now you can use your new operator in other files (like I did in main.swift).

like image 149
marosoaie Avatar answered Jun 01 '23 16:06

marosoaie


If you want a function to be accessed globally I would recommend to create a class that has static functions. For example

class Utils {
   static func yourFunction(){
      //Do your stuff here
   }
}

To use it :

Utils.yourfunction()
like image 21
unniverzal Avatar answered Jun 01 '23 18:06

unniverzal