Using Obj-C class extension in Swift? - objective-c

I added some Obj-C code (the excellent Expressions) to my Swift project using Xcode's Add files... but it did not ask me if I wanted to make a bridging header. So I made one myself in the Obj-C code's group, edited it to #import the single header I needed, and made sure that file was referenced in the Swift Compiler in Build Settings. I then looked through the Obj-C code and made sure the .m files were in the target - they were, and they're listed in Compile Sources.
The header in question contains this:
#interface NSNumber (Expression)
+ (NSNumber *)numberByParsingExpression:(NSString *)expression;
+ (NSNumber *)numberByParsingExpression:(NSString *)expression withVariables:(NSDictionary *)varDictionary;
#end
Now I am trying to call this code using the same basic syntax as this post:
let result = NSNumber.numberByParsingExpression(f.1)
along with several variations on the theme. But it won't compile, "Type 'NSNumber' has no member 'numberByParsingExpression'".
Did I miss a step here?

According to https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html
You can create a bridging header yourself by choosing File > New >
File > (iOS, watchOS, tvOS, or OS X) > Source > Header File.
You’ll need to edit the bridging header file to expose your
Objective-C code to your Swift code.
In your Objective-C bridging header file, import every Objective-C
header you want to expose to Swift. For example:
In Build Settings, in Swift Compiler - Code Generation, make sure the
Objective-C Bridging Header build setting under has a path to the
bridging header file. The path should be relative to your project,
similar to the way your Info.plist path is specified in Build
Settings. In most cases, you should not need to modify this setting.
Any public Objective-C headers listed in this bridging header file
will be visible to Swift. The Objective-C functionality will be
available in any Swift file within that target automatically, without
any import statements. Use your custom Objective-C code with the same
Swift syntax you use with system classes.
If you already did this correctly, and it still isn't working, try deleting the projects derived data, and clean building your project.

Ok, this turns out to be an Xcode peccadillo.
When you create the header file within the group, it actually places it physically in the source folder. So in my case the header was created in /project/subproject/.h although it appeared within Xcode to be part of the base folder, /project/.h.
So in fact there were two headers, one in the right place with nothing in it, and another in the wrong place that was the one that was being edited within Xcode. So you have to look at the file inspector to make sure it placed the bridging header in the right place!

Related

How to recognize touch inside SVG object in Swift?

I'm currently building an app where I need to recognize a touch point inside a SVG map. So I have a map with multiple rectangles and when the user touches one of these rectangles an action needs to be triggered. How can I solve this?
One option would be to mathematically calculate if the touch location lies in between a rectangle, but I am not a math genius.
My preferred option would be to use a framework. I found the SVGKit framework but unfortunately its written in Objective C.
You can use SVGKit for a Swift project. You have to use an umbrella header file, it is the 'master' header file for a framework.
Importing Objective-C into Swift
Access classes and other declarations from your Objective-C code in
Swift.
Overview
You can use Objective-C and Swift files together in a single project,
no matter which language the project used originally. This makes
creating mixed-language app and framework targets as straightforward
as creating an app or framework target written in a single language.
The process for using your Objective-C declarations from your Swift
code within mixed-language targets differs slightly depending on
whether you’re writing an app or a framework. Both processes are
described below.
Import Code Within an App Target
To import a set of Objective-C files into Swift code within the same
app target, you rely on an Objective-C bridging header file to expose
those files to Swift. Xcode offers to create this header when you add
a Swift file to an existing Objective-C app, or an Objective-C file to
an existing Swift app.
If you accept, Xcode creates the bridging header file along with the
file you were creating, and names it by using your product module name
followed by "-Bridging-Header.h". Alternatively, you can create a
bridging header yourself by choosing File > New > File >
[operating system] > Source > Header File.
Edit the bridging header to expose your Objective-C code to your Swift
code:
In your Objective-C bridging header, import every Objective-C header you want to expose to Swift.
In Build Settings, in Swift Compiler - Code Generation, make sure the Objective-C Bridging Header build setting has a path to the
bridging header file. The path should be relative to your project,
similar to the way your Info.plist path is specified in Build
Settings. In most cases, you won't need to modify this setting.
Any public Objective-C headers listed in the bridging header are
visible to Swift. The Objective-C declarations are automatically
available from any Swift file within that target, with no import
statements. Use classes and other declarations from your custom
Objective-C code with the same Swift syntax you use for system
classes.
Import Code Within a Framework Target
To use the Objective-C declarations in files in the same framework
target as your Swift code, you’ll need to import those files into the
Objective-C umbrella header—the master header for your framework.
Import your Objective-C files by configuring the umbrella header:
Under Build Settings, in Packaging, make sure the Defines Module setting for the framework target is set to Yes.
In the umbrella header, import every Objective-C header you want to expose to Swift.
Swift sees every header you expose publicly in your umbrella header.
The contents of the Objective-C files in that framework are
automatically available from any Swift file within that framework
target, with no import statements. Use classes and other declarations
from your Objective-C code with the same Swift syntax you use for
system classes.
Source
Additional information
How to include Objective-C frameworks in your Swift project

Adding objective c class that uses swift classes to bridging header Projectname_swift.h not found

I have an objective-c class that uses swift classes. It all works fine.
I wanted to import the objective-c class into a swift class, so I added its header file to the bridging header. All the sudden I got an error the Projectname_swift.h file is not found.
Any ideas how to resolve this issue?
Is it actually possible?
a circular reference has been created, making it so the Swift code is unable to compile (which leads to the canary error stating that the _Swift.h file is not found).
i have provided a more in depth answer to a similar questions here and here.
long story short, the documentation explicitly says not to this:
To avoid cyclical references, don’t import Swift code into an Objective-C header (.h) file. Instead, you can forward declare a Swift class or protocol to reference it in an Objective-C interface.
Forward declarations of Swift classes and protocols can only be used as types for method and property declarations.
in order to make your code compile again you will need to remove the #import "Projectname_Swift.h" line from the offending Objective-C header. ideally you can simply move the import statement into your .m file, however if you need to publicly expose the Swift class in your ObjC header, then you must forward declare it using #class SomeSwiftClass;.
Let the Xcode build the bridge file from Objective-C to Swift.
Create a temporary directory elsewhere. In there, you create a dummy Xcode Swift project, give the project name the same as your existing Current Project Name.
Then add new file, Objective-C (.m file). The XCode will prompt you to create a bridge header file, click on the create bridge file (the right most button).
Now you locate the header file location in Finder. Then drag into your Current Project of Interest, don't forget to checked the copy file if necessary option. Add necessary #import '.....' in the header file.
You should be good. If everything works fine, delete the dummy project.
Clean derived data. and then #import "ProjectName-Swift.h" in your objective c files.
Go to
Build Settings->Objective-C Generated Interface Header Name
and set the value to YourModule-Swift.h (this is usually already set, this is the filename you need to import on .m file #import "YourModule-Swift.h"
Go to Build Settings and search for "Defines Module", set both values to YES
Create a class in swift with prefix of #objc for example
#objc class mySwiftClass{...}
Build the project again
it will be better if you use error syntax or screen shot. you can simply try this
1. Goto your project on top of right navigation
2. select build settings from middle pain.
3. search for Objective-C bridging header
4. just below this you will find "Generated interface HeaderName"
5. add correct address of your swift file
6. clean and build the project.

Obj-C - Import (Swift Compiler Recognise?)

I'm migrating from Obj-C to Swift and have just migrated from PSGameScene.h and PSGameScene.m to GameScene.swift.
When I build the app, I get an error stating that PSGameScene isn't a recognised symbol.
GameScene.swift is added to the "compile list", I've tried adding GameSCene-swift.h to the source, but it doesn't see it..
Where am I going wrong?
I can confirm that both the bridging header and the .swift file area added to the compile scheme.
In the .h and .m files, it does recognise the class, and when I imoprt trying to use (GameScene-swift.s it complains that the file isn't there...
I'm. little lost...
Any posters would be helpful...
Cheers,
A
Sounds like you want to use your new Swift class in Objective-C, check out this answer about how to mix and match the two in the same project.
The gist is: import the generated -Swift.h header in your .m file that you want to use the Swift class on (you can't import it in a .h, check the above answer for more):
// SomeImplementationFile.m
#import "ProjectName-Swift.h"
You can double check the name of your -Swift.h header in Build Settings / Objective-C Generated Interface Header Name.
The issue turned out to be related to the build settings. As defines module was set to NO, it didn't like the import. When the DEFINES_MODULE (defines module) setting was set to YES it all clicked into place.
This probably happened as it related to an old project which spans back to Xcode 4 days. It appears that the newer releases of Xcode don't take into account some settings.
Thanks for the answers..

How to add Objective-C Bridging Header entry?

I have a Swift project and have add a cocoapod, which is written in Objective-C. It has header and implementation files. From what I understand, to use/import these files into my Swift files, I need to add a bridging file.
I found this site describing how to do this manually, since the Objective-C files are already part of my project (from the cocoapod).
http://www.learnswiftonline.com/getting-started/adding-swift-bridging-header/
1.) Navigate to your project build settings and find the “Swift Compiler – Code Generation” section. You may find it faster to type in “Swift Compiler” into the search box to narrow down the results.
2.) Next to “Objective-C Bridging Header” you will need to add the name/path of your header file. If your file resides in your project’s root folder simply put the name of the header file there.
I don't have a Objective-C Bridging Header in that section and it doesn't appear you can add new entries there.
I'm using Xcode 7.3.1. Anyone have some idea how this should be done?
Are you sure you looked at the correct Build Settings section, search with the keyword Swift compiler - General in the search field as describe below and then you can find it.
You need to create the header file first. It is a regular Objective-C header file and should be named <Your app or framework name>-Bridging-Header.h. For any Objective-C headers you want Swift to know about add an import statement to the newly created header file. Then follow your previous steps.
There is also a hidden header that gets created for you called <Your app or framework name>-Swift.h. If you need to access any Swift classes from an Objective-C file import this header.

Swift to Objective-C header not created in Xcode 6

I have recently been working to add Swift to an existing project, to get to try it out in a real-world fashion.
Upon adding a Swift source file to the project, I have no problems about getting the "Bridging Header", that is, Objective-C to Swift.
But the *-Swift.h header file that is supposed to expose Swift classes either marked #objc or subclasses of ObjC classes, is nowhere to be found :-(
I don't see any specific instructions on how to accomplish the usage of my new subclass, written in Swift, in my main app code (which is still Objective-C).
The app that I am lead developer of has a fairly large codebase (70.000 lines), so transitioning it in one go is out of the question.
Now it works.
Project must have a Product Module Name that does not include spaces.
Defines Module must be set to Yes in Build Settings, under Packaging.
Finally works. Thanks to everyone for the help :-)
I had a similar problem and found that you can only add
#import "ProductModuleName-Swift.h"
to obj-c .m files, not .h files for the umbrella header to be found
I found that I had to fix all build errors before it would generate the file.
The problem for me was that it was a chicken/egg problem, in that I didn't see any build errors until I'd actually commented out the #import statement:
//#import "ProductModuleName-Swift.h"
which revealed a bunch of other errors in my Swift code.
Once I fixed these new errors and got the source building successfully, I uncommented out the #import and bingo! The header was created and importing correctly :)
If you're like me you've probably got the header name wrong. After bashing my head for a while I looked for the file in DerivedData and sure enough it's there. On my setup (using the standard derived data folder, I believe):
cd ~/Library/Developer/Xcode/DerivedData
find * -iname '*Swift.h'
Will find it. If nothing in that folder matches then Xcode is not generating it.
I'm using Xcode Version 6.2 (6C86e)
If your project module name has spaces in it, you must replace the spaces with an underscore.
For instance, if your project name is "My Project", you would use:
#import "My_Project-Swift.h"
* The only important thing is: *
to use the defined "Product Module Name" in the target, followed by -Swift.h
#import <Product Module Name>-Swift.h
// in each ObjectiveC .m file having to use swift classes
// no matter in which swift files these classes sit.
No matter if "Defines Module" param is set to Yes or No or if "Product Module Name" Project is not set.
Reminder: Swift classes must deriving from NSObject or been tagged with #objc attribute in order to be exposed to ObjectiveC / Foundation || Cocoa ...
I wanted to add one more reason you might find an issue with this - I was creating a framework that mixed Swift and Objective-C code. I was not able to import the Swift classes outside the framework - I checked for the -Swift.h file and it was being generated but was empty.
The problem turned out to be very, very simple - I had not declared any of my Swift classes public! As soon as I added the public keyword to the classes, I was able to use them from classes inside and outside the framework.
Also of note, inside the framework (inside .m files only as another answer mentions) I had to import the -Swift.h file as:
#import <FrameworkName/FrameworkName-Swift.h>
I had the same problem. Seems like you have to adjust the settings (Defines Module and Product Module Name) before you add your first Swift file.
If you do it afterwards the "*-Swift.h" file will not be generated for this project even if you add further Swift files or delete the Swift file and create a new one.
Allow me to share my experiences trying to use Swift in an old objc project. I did not have to set Defines module to YES.
In my case I needed to manually make sure there was an objc Bridging Header. Only the generated interface header name was present in my build settings.
This lead to a MyApp-Swift.h file to being generated, but without any traces of my Swift classes.
The Apple documentation says that you will be prompted to create a bridging header when adding your first swift file. Well, I wasn't. I manually added a MyApp-Bridging-header.h file and pointed to it in the "Objective-C Bridging Header" field. That made my MyApp-Swift.h file become populated with my Swift classes.
Docs: Importing Swift into Objective-C
Here is another variation of the moduleName-Swift.h not being generated.
I decided to include IOS Charts in my project but did not want to mingle the sources in the same directory, so I placed the Charts Project folder next to my code's project folder. I dragged the Charts project into my Project's Navigator Bar and included the framework in the my project target's Embedded Binaries list in the General project settings and set the Embedded Content Contains Swift Code switch to yes in my project's Build Settings tab in the Build Options section.
My project's moduleName-Swift.h file would never generate no matter what other switches or settings suggested here. Finally, using Lou Z's method of seeking out the -Swift.h files, I saw that a Charts-Swift.h file was being generated deep in my project's xcode Build directory in Charts.framework/Headers/
The solution to using Daniel Gindi's ios-charts Swift package without including the code in my project's source directory was to add:
#import "Charts/Charts-Swift.h"
To the modules charting my project's data.
The file name is always preceded by your Target name. It is referred as Product name but practically it is the target name.
So if you want it to build for a new target be ready to expect that_target-Swift.h file.
One way to handle this is
Add a preprocessor for each of your target that is the name of your target itself (without spaces). Ex. MY_TARGET=1. Add this in Project settings->Build Settings->Preprocessor Macros for each of your targets.
If you are using a PCH file,
Add these lines in the PCH file
#if MY_TARGET==1
#include "My_Target-Swift.h"
#elif THAT_TARGET==1
#include "That_Target-Swift.h"
#endif
Advantage of using PCH file is that you don't have to include the headers everywhere.
If you are not using a PCH file, just add these same lines in a single header and include that header wherever you need to use the swift classes.
This should work just fine.
If Xcode is actually generating your -Swift.h header (deep inside DerivedData) but it doesn't refer to your Swift classes, make sure you also have a bridging header defined. The way I read the docs implied I only needed that for calling Objective-C from Swift, but it seems to be necessary for calling Swift from Objective-C too.
See my answer: https://stackoverflow.com/a/27972946/337392
EDIT: It is because of public vs. internal access modifiers, as I eventually found explained in the Apple docs:-
By default, the generated header contains interfaces for Swift
declarations marked with the public modifier. It also contains those
marked with the internal modifier if your app target has an
Objective-C bridging header.
Seconding what a lot of people have here, but adding a pertinent screen shot. Swift and Obj-C code can certainly live together. It's not an all or none game.
To access Swift files in your Objective-C, all you need to do is add this call to your Obj-C file (in the .m / implementation file):
#import "{product_module_name}-Swift.h"
(Where {product_module_name} represents the product module name of your project). Rather than try to guess your product module name or figure out corner cases with spaces and special characters, just go to the build settings tab in the project and type in "product module name" - the inspector will reveal yours to you. Mine was something I did not expect it to be. Check out this screen shot if you're confused.
And to get Obj-c code working in Swift, you just need to add a bridging header file and import the relevant Obj-C headers there.
This answer addresses the use-case where you may already have some Objective-C code that calls Swift classes and then you start receiving this error.
How To Fix Issue
The following steps ultimately resolved all of the issues for me. I read above someone mentioning the "chicken and the egg" and it is exactly that concept which led me to this procedure. This explicit process shows that one has to remove any Objective-C code referencing Swift classes until after the header is generated.
Comment out the #import "ProductModuleName-Swift.h" statement in
your Objective-C implementation file
Comment out any references in the Objective-C implementation file to
Swift Classes
Clean & Build
Resolve all errors/warnings
Remove the comment on the #import "ProductModuleName-Swift.h" statement
Clean & build (successfully or fix any remaining errors, verify that you are not referencing any Swift classes in Objective-C at this point. If so temporarily comment these out)
Verify that "ProductModuleName-Swift.h" is generated by Cmd-Clicking
on the class name of the #import "ProductModuleName-Swift.h" statement
Remove the comment on the code referencing Swift classes in the Objective-C implementation file.
Clean & Build as normal (the "ProductModuleName-Swift.h" should be
generated and your Objective-C code referencing Swift Classes can be
used as normal)
Nota Bene: The answers about changing spaces to underscores and the Defines Module to YES as given above still applies when performing this process, as do the rules specified in the Apple Documentation.
Bridging Header Path
In one error, the file ProductModuleName-Bridging-Header.h was not being found during the build process. This fact generated an error
< unknown>:0: error: bridging header
'/Users/Shared/Working/abc/abc-Bridging-Header.h' does not exist
Closer inspection of the error indicated that the file would never exist at the location described because it was actually located at (a wrong path)
'/Users/Shared/Working/abc/abc/abc-Bridging-Header.h'. a quick search of the target/projects build settings to make the correction manually and the abc-Swift.h file was again auto generated.
Ok, here are all the things you really need!
1.Remove all the swift files you have added, and compile the code, without any errors.
----------
----------
2.Go to the "Projects" build settings, and set the product module name.
Project must have a Product Module Name that does not include spaces.
----------
----------
3.Defines Module must be set to Yes in Build Settings, under Packaging, in your project, and not target!
----------
----------
4.Now create a swift file or a view controller, in file-> newFile->
----------
----------
It will ask to create a bridging-header, allow it to make one.
If you have declined it once, you will have to manually add a -Bridging-Header.h
5.Add #objc in the controller, to tell the compiler that there is some swift file, which needs to be exposed to ObjectiveC
----------
----------
6.Build the project and import #import "-Swift.h" in any of the objectiveC controller, and it will work! You can Command-click on it to see the actual file!
----------
----------
Hope this helps!
The most important thing is that This file is invisible!!! At least it is in Xcode6 beta5. There will be no such file named "YourModule-Swift.h" in your workspace. Just make sure you have module name and defines module set to yes, and use it in your Objective-C class.
You have to import a header in Objective-C classes, which is:
#import “ProductModuleName-Swift.h”
It is automatically generated, on the reference it says "Any Swift files in your target will be visible in Objective-C .m files containing this import statement."
An actual file in the project is not created ([ProductModuleName]-Swift.h). Cmd + Click on the import either generates it on-the-fly (and in-memory) so you can see how the linkage is done, or opens a file somewhere in some Xcode cache dir, but it's not in the project dir.
You need to set Defines Module project prop (in target's Build Settings) to Yes and if your module name has spaces or dashes - use _ in all imports of the [ProductModuleName]-Swift.h file.
You can import it in all .h and .m files where you use swift types or you can import it in the .pch.
So if my Module (project) is named "Test Project", I would import it like this, in the .pch file of my project (just there):
#import "Test_Project-Swift.h"
Just a heads up for anyone who used "." in there project name. Xcode will replace the "." with an underscore "_" for the Swift version of the bridging header file. Oddly enough the Bridging-Header.h that is generated does not replace the periods with underscores.
For example a project with the name My.Project would have the following Bridging Header file names.
Bridging-Header.h (Autogenerated)
My.Project-Bridging-Header.h
Swift.h
My_Project.h
I hope this helps anyone who used a period and was stuck like I was. This file can be found at the following location.
Macintosh HD/Users/user/Library/Developer/Xcode/DerivedData/My.Project-fntdulwpbhbbzdbyrkhanemcrfil/Build/Intermediates/My.Project.build/Debug-iphonesimulator/My.Project.build/DerivedSources
Take care,
Jon
Project must have a Module Name not including spaces.
Defines Module must be set to Yes in Build Settings, under Packaging.
commented out the #import statement:
If still you are having error in importing "ProductModuleName-Swift.h" then
//#import "ProductModuleName-Swift.h"
which revealed a bunch of other errors in my Swift code.
Once I fixed these new errors and got the source building successfully, I uncommented out the #import and bingo! The header was created and importing correctly :)
I found a trick that always works on me.
Create your #import "ProductModuleName-Swift.h" in your appDelegate.h file and in your ProductName-Prefix.pch file. If you don't have it in xcode 6 you can create it with this way Why isn't ProjectName-Prefix.pch created automatically in Xcode 6?
Command+shift+k to clean your code, if you receive an error about your "ProductModuleName-Swift.h" delete it from appDelegate.h file.
Clean your code again. Now everything will work like a charm
If you receive again error about the "ProductModuleName-Swift.h", now create again in appDelegate.h file and clean your code again.
Do this work (delete and create the "ProductModuleName-Swift.h" from appDelegate.h file and clean your code) everytime you receive this error to silent it.
I Found this solution
Create SwiftBridge.h
put #import “ProductModuleName-Swift.h”
Make this .h file public (important) Select the file -> In Show the file Inspector (right bar) -> Make it public
Now you can
#import "SwiftBridge.h"
instead of ProductModuleName-Swift.h
This's a workaround solution, for the next version of Xcode I think this problem will be solved.
Good luck
If you were able to build a project before, with no issues related to “ProductModuleName-Swift.h” not found error, and now you are getting that nasty errors again, the reason might sit in your recent changes.
For me this was by (accidental) incorrect .swift file encoding. Reverting changes and bringing the back manually, does the job.
I was having a hard time determining my module name/objective-c's import of swift's headers. I did read a lot of articles here too.
But the definitive answer for your project name with all its included special characters (be it '.' or a numeric or a space) - you can find the text that will work for you in the "Product Module Name" under the target's Build Settings.
For example my target name started with a numeric - "1mg" and the field mentioned above showed "_mg" as my module name.
so I used #import "_mg-Swift.h" and it worked.
This may be an obvious point (maybe too obvious), but you must have at least one swift file in the project for the header to generate. If you are writing boilerplate or config code with the intention of writing swift later the import won't work.
In my case I had to set the deployment target to at least “OS X 10.9” and the -Swift.h header was automatically generated. Keep in mind that you can get a lot of deprecation warnings when you change the deployment target version, especially when you have an older and very large Objective C code base. In our case we also had a lot of work to do in XIB files & view classes.
I had to delete WatchOS2 swift code from my Objective C project. And only after that XCode offered to generate -Swift.h
I had similar problem but my project was compiling before and suddenly got error after few files code change. It took me while to figure out why I am getting 'File not found' error for myproject-swift.h file. The code changes I had done had some errors. Xcode did not point put those error instead all time showing the 'File not found error'. Then got copy of previous version code and I compared with new code and merged file one by one. After each file merge complied the project to find the error. So bottom line is if you have error in your code Xcode may just display 'file not found error' for myproject-swift.h file. Most likely you have compilation error in your project. Clean those error and it will work.
If you're using something like Cocoapods (and working out of the workspace rather than the project) try opening the project and building it before opening the workspace and building. YMMV.
Sometimes you just need to unset and then set again the target membership on the obj-c .m file.