How to pass a Swift struct as a parameter to an Objective-C method
Asked Answered
B

3

12

I have an Objective-C method that accepts a parameter of type id and I want to pass it a Swift struct.

ObjcClass.m file:

@implementation ObjcClass
+ (void)addListener:(id)listener {
    // Do something with listener
}

DemoStruct.swift file:

struct DemoStruct {
    func registerAsListener() {
        ObjcClass.addListener(self) // Can't find a way to do this
    }
}

The compile error message I get:

Type 'DemoStruct' does not conform to protocol 'AnyObject'

So my question would be, how do I make an Objective-C method accept Any instead of AnyObject and is there such a thing?

Burp answered 17/2, 2015 at 17:27 Comment(0)
B
15

The best thing i found was to wrap in a Box class

public class Box<T> {
    let unbox: T
    init(_ value: T) {
        self.unbox = value
    } }
Burp answered 9/3, 2015 at 22:35 Comment(2)
Wow this is an elegant solution. Xcode 7 beta 3. I had to subclass NSObject.Docker
@Docker and Edward, how do you subclass it as NSObject? I must be doing someting wrong? public class Box<T> : NSObject no?Ragan
E
12

You can't do it.

Swift structs are not accessible from Objective-C. This is stated in the "Using Swift With Cocoa and Objective-C" book from Apple:

You’ll have access to anything within a class or protocol that’s marked with the @objc attribute as long as it’s compatible with Objective-C. This excludes Swift-only features such as those listed here:

  • Generics
  • Tuples
  • Enumerations defined in Swift
  • Structures defined in Swift
  • Top-level functions defined in Swift
  • Global variables defined in Swift
  • Typealiases defined in Swift
  • Swift-style variadics
  • Nested types
  • Curried functions

Excerpt From: Apple Inc. “Using Swift with Cocoa and Objective-C.” iBooks. https://itun.es/gb/1u3-0.l

Eisenstein answered 17/2, 2015 at 17:30 Comment(3)
Thanks @jrturton, What might be a good way to bypass that ? maybe a dummy wrapper class then ?Burp
Perhaps, or an objc-friendly representation you can pass out. Depends what you need it for in objective-c land reallyEisenstein
There has been an amendment about feature availability for Enums: "Enumerations defined in Swift without Int raw value type"Broadcaster
D
0

Complementing Edward Ashak's answer we can use the following extensions. So somewhere in the Objective-C part a container property can be declared:

// An object that holds our Swift struct instance:
@property (nonatomic, strong) NSObject* pocObject;

In the Swift part we declare struct itself and a bunch of helpers:

// The struct we are boxing inside pocObject:
struct POCWithCheck: Decodable {
 ...
}

@objc class POCWithCheckBox: NSObject {
  let unbox: POCWithCheck
    init(_ value: POCWithCheck) {
      self.unbox = value
    }
}

extension POCWithCheck {
  func asNSObject() -> NSObject {
    return POCWithCheckBox(self)
  }
}

extension NSObject {
  func asPOCWithCheck() -> POCWithCheck? {
    return (self as? POCWithCheckBox)?.unbox
  }
}
Delightful answered 26/11, 2021 at 8:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.