Saturday, February 21, 2015

Swift/Objective-C Interoperability - Behind the "Configure Bridging Header" dialog

Disclaimer: Yes, I know about the typo "briding" in screenshots, but I'm lazy to redo all, so please ignore and read the article in peace :-)

Apple officially supports mix-and-matching Obj-C and Swift code in same xcode project.

When you create a first ObjC in a Swift project or vice versa. Xcode ask your permission to create a special file called Bridging Header.

If you say Yes, xcode silently creates a new header file named YourProjectName-Bridging-Header.h and add to your project. If you observe it also modifies your project (.pbxproj) file.

From the diff, you can see that it adds three configurations

  1. Enable Clang Module,
  2. Swift Obj Briding Header and
  3. Swift Optimization Level.

How to add the Bridging Header file manually?

You can say No to xcode dialog for adding bridging file and still add the file manually.

Bridging Filename should follow the same convension used by xcode?

The answer is No.

While searching answer for this question I found that the bridging file has to be added to your project's main group not under any other group.

Eg., I try to add bridge.h to subgroup and got the error.

bridging header '/Users/palaniraja/Desktop/Data/MyWorkSpace/try/swiftbriding/bridge.h' does not exist

Well, I was wrong. If you add it to a different group you need to provide the correct path. For instance, in this case it has to be swiftbriding/bridge.h

Remember the three configurations added by xcode? when you set the Objective-C Bridging Header it add the other two (Enable module and Optimization level) without any additional steps.

Common Errors

  1. "... bridging header 'path_to/project/bridge.h' does not exist"

    Please check whether your bridge file is available and in correct path (typo is the number one culprit)

  2. "... error: use of unresolved identifier 'ClassName'"

    Check whether you had included the ObjC class you use is added/imported in your bridge.h file.

What is happening in build process?

Here is the screenshot of build steps with bridging and without bridging.

I've noticied that it failed when compiling the .m file which uses the swift object. So I was curious to see whether the CompileC is passing any additional argument when you provide a bridging file. To my surprise, the compilec is identical for both.

I believe, the Compile Swift source files step does the necessary magic by linking/exposing the swift files to objc.

Is there any difference in adding bridge file to a ObjC project / Swift project?

No

I have noticed only the project name is the only variable in this dialog.

How to use ObjC classes in Swift project?

  1. Setup the Bridging Header properly
  2. Import all your ObjC class headers in your bridge-header.h file

How to use Swift classes in ObjC project?

  1. Setup the Bridging Header properly. Yes it is required for Swift to ObjC as well
  2. Import the yourprojectname-swift.h in your ObjC file where you need to refer the swift classes.
  3. You do not have to create yourprojectname-swift.h file, the compiler will be creating the same in build phase.


Sunday, February 15, 2015

Image Slicing (Repeatable image) with Xcode Asset Catalog

Image slicing option in xcode asset catalog allows you to define resiziable area an image so it can be repeated to fit the object's height & width.
The same can be achieved with resizableImageWithCapInsets:UIEdgeInsetsMake but I always messup the arguments and usually we have to try a random number by measure the edges with image editor (eg., preview) [[UIImage imageNamed:@"image.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(bottom, top, left, right)];

output


Why

Deleted code is debugged code
  • One less line to maintain/debug
  • No need to create an IBOutlet to set image
  • You can refer the image in IB and preview right away.
  • For all states (in case of a button)

What is the Catch?

  • I don't know how to reset (inset) from xcode asset catalog itself.
  • Editing in UI again if you change the image is little cumbersome at times. (usually when you try to switch between horizontal/vertical/both)
You can still manually fine tune the inset arguments in code if required. (Right click on an image Show in Finder edit resizing object in Contents.json refer the screenshot)

There are three ways you could resize the image to fit your need.

  • Horizontal (3-part horizontal)
  • Vertical (3-part vertical)
  • Both (9-part)



For the first two options, it let you select non-repeatable left edge, resizable middle area, and repeatable right edge.

Horizontal slicing is best option if you have the asset that fit the height of your button/host view. If your host view (button in our case) match the width of the asset then you can do the same with vertical slicing.
If you want to truly want to repeat the image to fit dynamic size (width x height) then 9-part is the best option.

Slicing



Behind the scene



Step by Step





Links: