11

I have several simple structs written in swift inside .swift files. These structs are very simple and contain almost only Strings:

struct Letter {
   struct A {
      static let aSome : String = "descASome"
      static let aSomeMore : String = "descASomeMore"
   }
   struct B {
      static let bNow : String = "descBNow"
      static let bLater : String = "descBLater"
   }
...
}

I want to use those structs inside a project which contains Objective-C code because I'm writing a cross platform framework.

I have read: ObjectiveC - Swift interoperability by Apple which clearly states that Swift written structs can't be used by ObjectiveC. Excluded are (among other features):

Structures defined in Swift

Solution 1:

I have found a SO solution which solves the issue by using classes:

@objc class Letter : NSObject {
   @objc class A : NSObject {
      static let aSome : String = "descASome"
      static let aSomeMore : String = "descASomeMore"
   }
   @objc class B : NSObject {
      static let bNow : String = "descBNow"
      static let bLater : String = "descBLater"
   }
...
}

This solution works, however I have to rewrite all the structs to classes. They are also not lightweight like structs (among other things). Besides I feel like I am going backwards to solve the problem.

Q1. Is there any other way to use Swift structs inside ObjectiveC beside solution 1 which doesn't fit well for my project/situation? (enums can be used if their rawValue is Int)

Q2. Is there a way to use #define SomeConst for ObjectiveC access and stucts for Swift access like :

#if macOS // if Swift?
#endif
Cœur
  • 37,241
  • 25
  • 195
  • 267
Darkwonder
  • 1,149
  • 1
  • 13
  • 26
  • 1
    Your Q1 is a duplicate of https://stackoverflow.com/questions/26173234/how-to-use-swift-struct-in-objective-c. It is *documented* that Swift structs are not imported into Objective-C. – Martin R Jun 30 '17 at 11:43
  • I could edit the question but the answer was "as of now" - 2014... the solution isn't very good for my case (big app). – Darkwonder Jun 30 '17 at 11:46
  • If you know *"that Swift written structs can't be used by ObjectiveC"* then why do you ask *"Is there a way to use Swift structs inside ObjectiveC?"* – Martin R Jun 30 '17 at 11:48
  • I have edite the Q1 and question name. – Darkwonder Jun 30 '17 at 11:52
  • 1
    Swift structs are not imported to Objective-C. That's how it was in 2014 and still is. – But you can define string constants in Objective-C in a way that they are imported as enums to Swift. – Martin R Jun 30 '17 at 11:54
  • Could you please provide some code/link. I will accept it as answer if it still works. – Darkwonder Jun 30 '17 at 11:59
  • "imported as enums" was not quite right. "Imported Constant Enumerations and Structures" in https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithCAPIs.html is what I meant. – Martin R Jun 30 '17 at 12:14

2 Answers2

3

As of now, NO. You will need Classes to store model objects.

@objcMembers public class Car: NSObject {
    public var mileage: NSNumber?
}

@objcMember virtually converts them to Objective-c readable format and can be accessed from Objective-C classes. This will make your code interoperable.

Note: Make sure the class type is NSObject.

Shobhit C
  • 828
  • 10
  • 15
2

You can't do this without doing some rewriting: Swift structs are simply not visible from ObjC.

You need to write an ObjC-visible Swift class to expose the values, sort of the inverse of Swift Foundation's "overlay" types.

One option is to follow the structure of the Swift code as closely as possible. Note that nested classes are disallowed, and that the ObjC "overlay" must have a different name than the Swift struct. This is unfortunate but impossible to work around, since this Swift code is visible in the same places that the original struct is.

import Foundation

@objc class OCLetters : NSObject {
    static let A = _A.self
    static let B = _B.self
}

@objc class _A : NSObject {
    static let some = Letters.A.some
    static let someMore = Letters.A.someMore
}

@objc class _B : NSObject {
    static let now = Letters.B.now
    static let later = Letters.B.later
}

If you want to use dot notation for the values in your ObjC code, however, this won't work. This is probably a bug, but the .some in OCLetters.A.some is treated as a struct member reference, which fails. (Changing the properties to computed class properties doesn't work either.) You must write [[OCLetters A] some] (or [OCLetters.A some]).

To be able to use dot notation, you'll have to change the structure slightly so that the properties are actually instances:

import Foundation

@objc class OCLetters : NSObject {
    static let A = _A()
    static let B = _B()
}

@objc class _A : NSObject {
    let some = Letters.A.some
    let someMore = Letters.A.someMore
}

@objc class _B : NSObject {
    let now = Letters.B.now
    let later = Letters.B.later
}

Also note that you unfortunately can't restrict the visibility in ObjC of the helper _A and _B classes, because if they are not visible, neither will OCLetters's properties be.

koen
  • 5,383
  • 7
  • 50
  • 89
jscs
  • 63,694
  • 13
  • 151
  • 195