Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to use Swift structs in Objective-C without making them Classes?

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
like image 869
Darkwonder Avatar asked Jun 30 '17 11:06

Darkwonder


People also ask

Can I use Swift struct in Objective-C?

Swift Struct is not available in Objective-C. Enum only Int types are available in Objective-C. Swift functions with default parameter values are available in Objective-C but you will have to give values to each parameter.

Can you use structs in Objective-C?

You can use regular C structs all you want. Your example tries to put references to an Objective-C object, NSString , into a struct , which is incompatible with ARC. Structs are typically used for simple data structures. Examples that you are likely to come across in Objective-C code are CGPoint and CGRect .

How do I access a Swift file in Objective-C?

To access and use swift classes or libraries in objective-c files start with an objective-c project that already contains some files. Add a new Swift file to the project. In the menu select File>New>File… then select Swift File, instead of Cocoa Touch Class. Name the file and hit create.

Why does SwiftUI use structs instead of classes?

First, there is an element of performance: structs are simpler and faster than classes. I say an element of performance because lots of people think this is the primary reason SwiftUI uses structs, when really it's just one part of the bigger picture.


Video Answer


2 Answers

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.

like image 97
Shobhit C Avatar answered Oct 18 '22 22:10

Shobhit C


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.

like image 1
jscs Avatar answered Oct 18 '22 23:10

jscs