2

I am migrating code from Objective-C to Swift 4.0. Here I have some float #define constants related to my deviceHeight in Specific Objective-C header class. While accessing this #define giving error "Use of unresolved identifier". When I use Objective-C string #define identifier it's easily accessible within Swift class.

Not accessible in Swift4

#define PHONE_IPHONE10 PHONE_UISCREEN_HEIGHT==812.0f

Accessible in Swift4

#define ERROR @"Some error occured. Please try later."

Help me with your comments or solution.

Nirav Jain
  • 5,088
  • 5
  • 40
  • 61
  • Why don't you use constants? Changing `#define` to constant is easy: `static CGFloat const PHONE_IPHONE10 PHONE_UISCREEN_HEIGHT = 812.;` then you can also use consts in `swift` Getting phone screen you can also achieve programically. https://stackoverflow.com/questions/14475008/how-to-get-iphone-screen-size-programatically – Piotr Wasilewicz Mar 22 '18 at 06:59
  • But why Swift has restricted for float and not for string #define? – Nirav Jain Mar 22 '18 at 07:02
  • Because it is dangerous. Imagine this situation: `#define aa = 10` then somewhere in your code could be `let anotherVar = "smaall value"` anotherVar will be `sm10ll value` – Piotr Wasilewicz Mar 22 '18 at 07:03
  • I hope that I get this solution in Swift 4.2 or 5...:D – Nirav Jain Mar 22 '18 at 07:04
  • No, you will not, because Swift is safe (if we talk about types) – Piotr Wasilewicz Mar 22 '18 at 07:06

2 Answers2

1

The reason this imports to Swift...

#define ERROR @"Some error occured. Please try later."

...is that it’s semantically equivalent to a constant declaration. That is, it permanently associates that string-literal value with the name ERROR. The Swift compiler recognizes that you’re using the C preprocessor to define a constant, and translates it to a Swift constant.

(Even though you could—and probably should—define C global constants without the preprocessor, Swift recognizes that there’s a long tradition of using #define instead, and imports it anyway.)


The reason this doesn’t import to Swift...

#define PHONE_IPHONE10 PHONE_UISCREEN_HEIGHT==812.0f

...is that this is a preprocessor macro. It doesn’t statically map a name to a value. Instead, it tells C that wherever it sees your name PHONE_IPHONE10, it should substitute the expression PHONE_UISCREEN_HEIGHT==812.0f. Presumably PHONE_UISCREEN_HEIGHT is itself a macro, so the whole thing expands to a chain of method calls and an equality comparison.

Swift itself doesn’t do preprocessor macros, or anything like such, so it doesn’t import them from C.

A close equivalent would be to redefine this logic using a computed property or function (and the idiomatic way to do that in Swift would be as a static member on a type, not a global symbol). Something like this:

extension UIDevice {
    class var isMaybeiPhoneX: Bool {
        return false // or some logic based on UIScreen.main.size
    }
}

But be warned, the whole idea of conditionally changing your app’s UI or behavior based on a specific screen height check is fraught with peril. Tried Auto Layout?

rickster
  • 124,678
  • 26
  • 272
  • 326
-1

To achieve similar functionality I created Constants.swift file with this structure:

struct Constants {
    struct phoneHeights {
        static let PHONE_UISCREEN_HEIGHT = 812.0
        //some others consts
    }

    struct iPhoneX {
        static let statusBarHeight: CGFloat = 44
        //some others consts
    }
}

Or simply:

struct Constants {
    static let PHONE_UISCREEN_HEIGHT = 812.0
    static let statusBarHeight: CGFloat = 44
}

And for type safety in Swift, you can read here.

Piotr Wasilewicz
  • 1,751
  • 2
  • 15
  • 26
  • That is not the same as the above macro. The above macro is a comparison, not an assignment. Your answer would be correct if the original code was `#define PHONE_UISCREEN_HEIGHT 812.0f`. – uliwitness Jul 28 '18 at 02:10
  • @uliwitness Yes and because of that I wrote "similar functionality" – Piotr Wasilewicz Jul 28 '18 at 10:36