By changing the 'PRODUCT_MODULE_NAME' build setting + adding XCTest.h import in the bridging header file, I was able to make this work.
On my previous post about Swift, I mentioned that one of the biggest issues I had with Swift is the fact I get a compilation error on my unit tests target if I ever use the import "MyProject-Swift.h" in a file that is included in this target (whether it's a test case or production code).
I also mentioned this is a big issue in the Swift talk I gave in Reversim Summit 2015 (in Hebrew).
Well, turns out I was wrong (or at least - it can be fixed).
To fully understand the solution, lets' first make sure you understand the problem and why this is such a big issue for me.
I'll try to show a concrete example so you could understand it, and maybe because all names are stupid it may be harder to relate to, but believe me - if you write new swift code in a real life Objective-C project, you will eventually need to use it SOMEWHERE from your Objective-C code.
Class A is written in Objective-C and has a unit test.
It also internally uses a class called B, written in Objective-C and doesn't have a unit test.
I now decided I want to add a new class named C. It's written in Swift and I add a unit test for it in Swift.
Now I want to use class C in class B.
I need to add "MyProject-Swift.h" to B's code for it to work, right?
Right.
So here's what we've come up with by now:
If I build and run my app, everything is fine.
If I build and run my unit tests target, I get the following error:
'MyProject-Swift.h' file not found |
When I originally found out about this (somewhere during the early days of Xcode 6), I was helpless and devastated.
There were only 3 workarounds I could think of and apply to my projects:
- Not importing "MyProject-Swift.h", and therefore having to use tricks like NSClassFromString(@"C") and performSelector - UGLY as hell
- Removing B.m from the Test target (by unchecking the target in the "Target Membership" section of the File Inspector) - Might work for certain cases, but as you see in my example, this means ATest can't compile as it uses A that uses B (that uses Swift code). So if I have enough coverage in my unit tests this is hopeless.
- Porting the whole project to Swift - Too expensive.
This essentially meant that I used swift only for very isolated features in my project, which was very upsetting.
The reason I originally came to the conclusion that it can't be fixed and there aren't any other workarounds, apart from banging my head for a long time about it without success, was an answer on SO basically saying that Apple declared it's a known issue.
In a weird coincidence, just several hours before I decided I should tackle this issue again, a new answer was posted to the same question. It didn't quite solve my problem (I think it's because I didn't move to Xcode 6.3 yet for the problematic project), but it gave me the hope and the direction to a solution!
The Solution
What essentially happens, is that the name of the generated header file that contains all the exported classes from Swift to Objective-C, is called "${PRODUCT_MODULE_NAME}-Swift.h"
What's ${PRODUCT_MODULE_NAME}? By default, Xcode sets it to be the same as the ${TARGET_NAME}, meaning: MyProject-Swift.h for the App target, and MyProjectTests-Swift.h for the test target.
So, we could use some #ifdef statements each time we want to include the generated Swift header, but this is a terrible solution. Instead, I manually changed the product module name the following way:
PRODUCT_MODULE_NAME = "MyProject" |
That's it. For the example project I created for this post it was all I needed to do for solving the problem.
In my real project however, possibly because it was created with an older version of Xcode, I had another issue that I thought was worth mentioning - an issue of Xcode suddenly not running my Swift unit tests (CTest.swift in this example). It was complaining about not finding XCTestCase in the generated MyProject-Swift.h file.
What eventually solved it for me, is adding an XCTest import in my "MyProjectTests-Bridging-Header.h" file in the following way:
Add #import <XCTest/XCTest.h> to MyProjectTests-Bridging-Header.h
|
And that's it - problem solved.
BTW
If you are having problems with the other way around (Swift code importing Objective-C code in Unit Tests), I recommend reading the following post.
Also, if you have found this post interesting, you should follow me on twitter and listen to my podcast (in Hebrew).
Hi thanks for the post. I'm in a similar situation (trying to write swift tests including Obj-C files that use Swift code) and I got past the error you're getting by following this SO post: http://stackoverflow.com/questions/26473058/ios-myproject-swift-h-file-not-found-when-running-unit-tests-for-swift/29111547#29111547
ReplyDeleteHowever I'm now getting a different type of linker error:
"_OBJC_CLASS_$__TtC10AppName20ClassA", referenced from:
objc-class-ref in ClassB.o"
Any idea what this could be? Thanks!
I'm the same problem here. Did you manage to solve this?
DeleteThanks
This comment has been removed by the author.
DeleteYes
ReplyDeleteSee tl;dr at the beginning
Hi,
ReplyDeleteThanks for the post,Really you given a valuable information.worth to read this type of articles .very grateful to you for sharing this article.
Thank you.
oracle fusion training
Pretty article! I found some useful information in your blog, it was awesome to read, thanks for sharing this great content to my vision, keep sharing..
ReplyDeleteMobile App Development Company
Mobile App Development Company in India
Android app Development Company
ios app development Company
Mobile App Development Companies
This article is very much helpful and i hope this will be an useful information for the needed one.Keep on updating these kinds of informative things... iPhone Development Company
ReplyDeletethank you for a great post.
ReplyDeleteAndroid App Development Houston
I'm looking for good blog sites to study. I was looking on the search engines and found your blog site. I like your design of high quality blog sites, as well as your display capabilities. Keep doing it.
ReplyDeleteDedicatedHosting4u.com
Hey Good Post!! Thank You For Sharing!!!Good Blog.Its really helpful for me, waiting for a new post. Keep Blogging!
ReplyDeletewill help you more:
Hire some best dancers for your wedding party event or birthday celebration.
Contact Dynamic Hip-Hop And Western Dance Institute, Indore.
Thanks for sharing the information.
ReplyDeleteAndroid App development & iOS App development company in Switzerland-Bern
Artificial Intelligence & Iot app development company in Switzerland
Thanks for sharing such a nice information and it is really useful
ReplyDeleteDigital Transformation in Education industry
https://whitelabelfox.com/ubereats-clone-app/
ReplyDeletekırşehir
ReplyDeletekırıkkale
manisa
tokat
urfa
JVGM
Thank you for shedding light on this technology. I will be sharing this article with my friends and colleagues who are passionate about optimizing their free xmltv source. Keep up the excellent work!
ReplyDeleteTu contribución añade una maravillosa capa de positividad a nuestro blog, ¡gracias! He visto una mejora notable en mi velocidad de clic desde que utilicé la pruebaContador De Clicks aquí. ¿Listo para ver tu progreso? ¡Haga clic para realizar la prueba ahora!
ReplyDeleteWow, this was super insightful. I can't thank you enough! visit this profile coreball for more informative content.I’ve been searching for a fun and quick game, and I’m glad I found Coreball on this site. The gameplay is seamless, and I love how easy it is to navigate through the different levels. Definitely one of the better game sites I’ve visited!
ReplyDelete