42

The preprocessor macro's are pretty commonly seen in the SwiftUI official tutorials/videos, e.g.:

#if DEBUG
struct ContentView_Previews : PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
#endif

Are those needed? The compiler can surely see that the struct isn't used internally and omit the whole struct since the access modifier is implicit internal right? I think that everything that conforms to PreviewProvider can be removed away, but maybe that isn't the case for every conforming object, but if it isn't used, why does Apple decides to include the preprocessor macro's?

I tried to run it in release mode and locate the compiled class in the derived data folder, but I don't understand anything about it (.o file). Can anyone confirm if we really need to include the macros to omit unused code (the ContentView_Previews type doesn't get used anywhere in the code expect for previewing which isn't used in the release build anyway) in the release build?

J. Doe
  • 12,159
  • 9
  • 60
  • 114

6 Answers6

35

NOTE: To be extra clear, you DO NOT need to wrap your preview providers in #if DEBUG conditionals. They are removed from your production build.

I'm a little late, but I just had to make note of this because the confusion is all over the web and it turns out to be quite comical. The release note was under "Resolved Issues" and the title of the resolved ticket was "PreviewProviders aren’t properly removed from built products when archived. (51539802)".

Yeah, it all makes sense now.

The still The proof

Annnd Just in case you think they may have changed it later..... more proof

(I'm thorough... maybe too much so)

Dave Arel
  • 459
  • 4
  • 5
  • 4
    I had to add DEBUG conditions if I use code from PreviewContent folder. – Arpit May 11 '21 at 19:08
  • 8
    I'm on Xcode 14.2, and am seeing what may be a regression from Xcode 11's fix: "Any iOS Device" builds succeed, but Archive builds _do_ include PreviewProviders. And in my case, those PreviewProviders that are normally excluded reference some debug sample data variables wrapped with `#if DEBUG/#endif`, so Archive builds fail. All other build types succeed. Filed with Apple as FB11920041. – Collin Allen Jan 05 '23 at 05:05
21

For your particular case you can remove the #if DEBUG macro, but the issues comes when you want to use some mocks that are inside #if DEBUG macros. The build will fail for Release, because looks like Xcode will still try to build the PreviewProvider, most likely after it is build it strips or unlinks the code from the Release artifact.

#if DEBUG

class MyServiceMock: ServiceMockType {
    ...
}

#endif

// Will fail when you try to release.

struct ContentView_Previews : PreviewProvider {
    static var previews: some View {
        ContentView(service: MyServiceMock())
    }
}

This will work just fine for tests and for preview, but will fail when you try to release.

Despite they are not necessary, you need them if you use any code declared only for Debug. My suggestion is to keep them if you have code used in preview that is available only for debug.

#if DEBUG

class MyServiceMock: ServiceMockType {
    ...
}

#endif

...

#if DEBUG
struct ContentView_Previews : PreviewProvider {
    static var previews: some View {
        ContentView(service: MyServiceMock())
    }
}
#endif
Mihai Georgescu
  • 674
  • 8
  • 20
4

It seems to be removed from the 11 GM Seed. The GM seed release notes say (under Resolved Issues):

"The #if/#endif compiler conditionals surrounding PreviewProvider types have been removed from SwiftUI templates. PreviewProviders aren’t properly removed from built products when archived. (51539802)"

Not sure if this means the preview providers aren't currently removed or they fixed the issue and now remove them. I suppose if the template code removes the #if it means Apple believes it is no longer necessary.

GilroyKilroy
  • 847
  • 10
  • 17
  • 1
    I just archived a SwiftUI app and had to add the compiler conditionals around the PreviewProviders for it to work. This may be because I use mock data within compiler conditionals that the PreviewProviders reference though. – Iron John Bonney Mar 06 '20 at 18:30
3

Xcode 11.2 and higher do not need the #if DEBUG so, you would do the following and remove the #if DEBUG around the PreviewProvider

struct ContentView: View {
    var body: some View {
        NavigationView {
            List {
                Text("First Row")
                Text("First Row")
                Text("First Row")
                Text("First Row")
            }.navigationBarTitle(Text("Dynamic List"))
        }
    }

}



struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
Arunabh Das
  • 13,212
  • 21
  • 86
  • 109
  • 2
    Any resources you base this answer on? – J. Doe Nov 12 '19 at 15:14
  • 1
    There is a thread here : https://forums.swift.org/t/swiftui-previewprovider-no-longer-surrounded-with-if-debug-endif-what-does-this-mean/29943/2 which talks about stripping out of PreviewProvider subclasses – Arunabh Das Nov 23 '19 at 16:41
  • @ Arunabh Das, work on SwiftUI with latest Xcode and iOS version, so does it mean ```PreviewProvider``` is needed for both debug and release mode now? – Zhou Haibo Feb 15 '20 at 02:34
0

In my case: Xcode 13.2.1

I moved some preview only mocks to development asset and the release build started to fail. The compile error is about missing mocks in preview code. I think #if DEBUG macro is still necessary

Bill Chan
  • 3,199
  • 36
  • 32
-1

You do not need to delete that. DEBUG is a custom flag that is added automatically to Your Target -> Build Settings -> Active compilation Conditions. This flag is exist only for Debug configuration, for release build you will use Release configuration that doesn't have this flag.

If the flag doesn't exist - the code will be omitted

Read more here in section "The DEBUG preprocessor macro"

DenFav
  • 2,683
  • 1
  • 18
  • 27
  • 1
    First you say: "You do not need to delete that" and after that: "If the flag doesn't exist - the code will be omitted" so I am not sure that if the flag isn't there, the code will be omitted. Do you have any references that supports your thoughts? – J. Doe Jun 07 '19 at 12:39
  • 2
    I think you’re misunderstanding the question. OP is asking if the `if DEBUG` `endif` preprocessor is really necessary in this case. The point is that the preview code is obviously debug code, so do we need to explicitly label it as debug code, or is the compiler smart enough to figure that out and omit it from the output build without the macro? – Nate Jun 07 '19 at 13:09
  • You are right. I missed the core question. But I believe if we will delete this #if the code inside it will be compiled even for the Release configuration, but won't be used. As the result it will increase app size(or something). It is similar to @IBDesignable behaviour(so Apple may replace #if #endif with something like `@PreviewProvider` modifier. – DenFav Jun 07 '19 at 13:29
  • Xcode 11.2.0 requires that you delete the #if DEBUG flag around ContentView_Previews: PreviewProvider – Arunabh Das Nov 12 '19 at 15:08