Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Know at runtime that you are running in IBDesignable

(programming in swift 2)

In my iOS application I am using frameworks. I am also using the IBDesignable feature with great success. I have a bunch of views and buttons in frameworks that are IBDesignable and thus render nicely on the screen of interface builder.

Problem is that one of these views executes code when its initialized that will do an assertion if its being run just in the context of the IBDesignable interfacebuilder (executed just to render the IB screen). The reason for the assertion is valid, and really does not matter, bottom line is that I do not want to loose this functionality during "normal" operation.

My idea for a solution is to know when the code is being executed just for rendering in IB for IBDesignable mode, and thus build in a switch to not/do the assert.

I tried using the #if !TARGET_INTERFACE_BUILDER but this is not working, as this is a preprocessor directive and thus only evaluated a compile time, and the frameworks are precompiled (when used in the actual app).

I also thought about using prepareForInterfaceBuilder() but this is not applicable because the class throwing the assert has nothing todo with UIView itself.

Is there a function or any other way to check AT RUNTIME (in a framework) that your code is being run as part of IB screen rendering for IBDesignable mode?

like image 572
HixField Avatar asked Feb 23 '16 09:02

HixField


2 Answers

After testing a few dozens solutions, I found the following to work reliably:

/**
 Returns true if the code is being executed as part of the Interface Builder IBDesignable rendering,
 so not for testing the app but just for rendering the controls in the IB window. You can use this
 to do special processing in this case.
*/
public func runningInInterfaceBuilder() -> Bool {
    //get the mainbundles id
    guard let bundleId = NSBundle.mainBundle().bundleIdentifier else {
        //if we don't have a bundle id we are assuming we are running under IBDesignable mode
        return true
    }
    //when running under xCode/IBDesignable the bundle is something like
    //com.apple.InterfaceBuilder.IBCocoaTouchPlugin.IBCocoaTouchTool
    //so we check for the com.apple. to see if we are running in IBDesignable rendering mode
    //if you are making an app for apple itself this would not work, but we can live with that :)
    return bundleId.rangeOfString("com.apple.") != nil
}
like image 114
HixField Avatar answered Nov 07 '22 09:11

HixField


SWIFT 4 version

    /**
     Returns true if the code is being executed as part of the Interface Builder IBDesignable rendering,
     so not for testing the app but just for rendering the controls in the IB window. You can use this
     to do special processing in this case.
     */
    public func runningInInterfaceBuilder() -> Bool {
        //get the mainbundles id
        guard let bundleId = Bundle.main.bundleIdentifier else {
            //if we don't have a bundle id we are assuming we are running under IBDesignable mode
            return true
        }
        //when running under xCode/IBDesignable the bundle is something like
        //com.apple.InterfaceBuilder.IBCocoaTouchPlugin.IBCocoaTouchTool
        //so we check for the com.apple. to see if we are running in IBDesignable rendering mode
        //if you are making an app for apple itself this would not work, but we can live with that :)
        return bundleId.contains("com.apple.")
    }
like image 3
Oscar van der Meer Avatar answered Nov 07 '22 09:11

Oscar van der Meer