0
votes

Class is written in Swift,

@objc class Test: NSObject {

    @objc func testBoolean() -> Bool {
        return true
    }

    @objc func testOptionalBoolean() -> Bool? {
        return true
    }

    @objc func testThrowableBoolean() throws -> Bool {
        return true
    }

    @objc func testThrowableOptionalBoolean() throws -> Bool? {
        return true
    }
}

Among these functions only first function is compilable.

Other functions compiler errors,

testOptionalBoolean: Method cannot be marked @objc because its result type cannot be represented in Objective-C

testThrowableBoolean: Throwing method cannot be marked @objc because it returns a value of type 'Bool'; return 'Void' or a type that bridges to an Objective-C class

testThrowableOptionalBoolean: Method cannot be marked @objc because its result type cannot be represented in Objective-C

What is the proper way to make all of functions available for objc callers?

2
You still want to call these the same way in Swift, right? - Sweeper
@Sweeper yes offcourse - Sazzad Hissain Khan
Would you mind creating copies of those methods (not copies of their bodies, just the header)? For example, you can write another method @objc func testOptionalBoolean() -> NSNumber? { return testOptionalBoolean().map(NSNumber.init(value:)) } But I know that some people doesn't like having two methods with the same name and parameters. - Sweeper
Return NSNumber where compiler complains - Cy-4AH

2 Answers

1
votes

The error messages are quite clear:

  1. An optional scalar type cannot be used as a return type in ObjC because only objects are nullable.
  2. To be able to convert a throwing Swift function to the ObjC inout NSError syntax the return type must be AnyObject (a class) in terms of Swift.

You can replace the Bool types with NSNumber for example

@objc func testOptionalBoolean() -> NSNumber? {
    return true // Yes, returning a Swift Bool is valid
}

but even with NSNumber the function testThrowableOptionalBoolean does not compile because the design of a throwing function is to return a non-optional on success

1
votes

SE-0230 modifies the way try? works so that nested optionals are flattened to become regular optionals. This makes it work the same way as optional chaining and conditional typecasts, both of which flatten optionals in earlier Swift versions.

Hackingwithswift Article


You can create an object as a wrapper.

@objc class Test: NSObject {

    @objc func testBoolean() -> Bool {
        return true
    }

    @objc func testOptionalBoolean() -> BooleanWrapper? {
        return BooleanWrapper(true)
    }

    @objc func testThrowableBoolean() throws -> BooleanWrapper {
        return BooleanWrapper(true)
    }
}

Usage

if let wrapper = try? test.testThrowableBoolean() {
    print(wrapper.bool)
}

Wrapper

@objc class BooleanWrapper: NSObject {

    let bool: Bool

    init(_ bool: Bool) {
        self.bool = bool
    }
}