Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can method in Swift with inout parameter be used in Objective-C?

I want

func foo(inout stop: Bool) -> Void {
    // ...
}

use in my Objective-C part. But it is never generated in Module-Swift.h header. If I mark it with @objc, the

Method cannot be marked @objc because the type of the parameter cannot be represented in Objective-C

error occurs.

like image 467
user500 Avatar asked Oct 09 '14 21:10

user500


People also ask

How do you pass Inout parameters 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 a good use case for an inout parameter in Swift?

A good use case will be swap function that it will modify the passed-in parameters. Swift 3+ Note: Starting in Swift 3, the inout keyword must come after the colon and before the type. For example, Swift 3+ now requires func changeChar(char: inout Character) .

What does Inout mean in Swift?

All parameters passed into a Swift function are constants, so you can't change them. If you want, you can pass in one or more parameters as inout , which means they can be changed inside your function, and those changes reflect in the original value outside the function.


2 Answers

You can't use an inout parameter when bridging with Objective-C, but you can do something similar if you use an UnsafeMutablePointer<T> (T would be Bool in your case). It would look something like this:

@objc func foo(stop: UnsafeMutablePointer<Bool>) -> Void {
    if stop != nil {
        // Use the .pointee property to get or set the actual value stop points to
        stop.pointee = true
    }
}

Example

TestClass.swift:

public class TestClass: NSObject {
    @objc func foo(stop: UnsafeMutablePointer<Bool>) -> Void {
        stop.pointee = true
    }
}

Objective-C:

TestClass *test = [[TestClass alloc] init];
BOOL stop = false;
[test foo:&stop];
// stop is YES here
like image 110
Mike S Avatar answered Oct 05 '22 19:10

Mike S


Similarly to what happening with generics, inout is not objc-compatible.

One possible workaround is to embed your parameter(s) in a class (which is a reference type, hence passed by pointer and not by value):

@objc class MyFuncParams {
    var stop: Bool

    init(stop: Bool) {
        self.stop = stop
    }
}

and define the function to accept an instance of that class:

func changeParam(params: MyFuncParams) {
    params.stop = true
}

Not an elegant way to solve the problem, but what's important is that it should work (never tried myself though).

like image 23
Antonio Avatar answered Oct 05 '22 18:10

Antonio