I want to make an app in Swift that simply record via the mic of the iPhone and then play the sound recorded.
For that, I'd like to use the lib Superpowered that is a static library with header files.
For that, I tried to drag and drop the .a and headers files in my project (Xcode create for me a bridging header file), add the .a in "Linked Frameworks and Libraries" in Xcode > Target > General (and so in Xcode > Target > Build phases > "Link Binary With Libraries" too) and index the .h files path in Xcode > Target > Build Settings > Search Paths > Library Search Paths.
But with that I have the error "ld: symbol(s) not found for architecture arm64"
Exactly the same as here XCode: Undefined symbols for architecture arm64 error and I tried all the solutions that I found on the web for that, still no way to compile.
SO !
Superpowered gives us a sample app to show how to mix Objective-C++ and use their lib within a Swift project (Here's a link to the git if you want https://github.com/superpoweredSDK/Low-Latency-Android-Audio-iOS-Audio-Engine).
Here is some screenshots of the sample project with what I understand and what I don't :
The Bridging-Header-File with the prototypes of the methods of the lib that I want to use within my Swift code (I don't like this but if it's the only way...).
The viewController file where the code in Swift is, and where I can create a Superpowered object thank's to the Bridging-Header-File, and call the methods that I've put in it.
And wtf I don't even understand why this Objective-C++ file is here and what it contains. It comes out from nowhere, not even their lib files.
So with this sample project in mind, I've created my own project, here is some screenshots :
The same Bridging-Header-File that in the sample project except that I include SuperpoweredIOSAudioIO.h so I can use SuperpoweredIOSAudioIODelegate.
My viewController file where the code in Swift is, and where I can create a Superpowered object thank's to the Bridging-Header-File, and call the methods that I've put in it.
Until here, it's great, except that I can't for exemple create a SuperpoweredRecorder object. If I try to include the SuperpoweredRecorder.h file in my Bridging-Header-File I have these errors :
So I saw that it is because SuperpoweredRecorder.h includes some .cpp files and I have to create a wrapper for cpp (a little bit like I did with the bridging header, no ?) but that includes a .h and a .mm file and I don't know what I have to put in that .mm file (the code of SuperpoweredRecorder.cpp ? But I don't have access to it)
So yes, I'm a little bit confused with all that stuff, can you help me to understand how can I use all the Superpowered lib in my Swift project please ?
As I said in comment to #OmniProg, I had a little conversation with the CTO of Superpowered that helped me a lot to find the solution below.
So, as Swift cannot interact directly with C++ but can with Objective-C, I had to create objects in Objective-C++ (.mm file, a mix between C++ and Objective-C) that wrap C++ classes of the lib Superpowered.
Here is an example with the SuperpoweredRecorder object from the lib :
Here I create a .h file where I prototype my wrapper with the name SuperpoweredRecorderWrapped, and I also prototype in it all the methods of the SuperpoweredRecorder of the lib that I want to use.
Then I create a new .m file that I rename .mm and I implement SuperpoweredRecorderWrapped on it.
I import both SuperpoweredRecorderWrapped.h and SuperpoweredRecorder.h.
I create a SuperpoweredRecorder object as property named _wrapped and in my methods, I call the corresponding method of the _wrapped object.
With that, when I'll call start of a SuperpoweredRecorderWrapped in my Swift code, this one will call start of _wrapped, a SuperpoweredRecorder object. See the trick ?
And finally I include all the wrapped classes in my Bridging-Header, like that I can instantiate my wrapped objects from Swift.
NOTE: All the C++ code HAVE to be in .mm files, that's why I make my #include of .h that contains C++ code in my .mm file and not in my .h file.
I haven't programmed in Objective-C++, but I do have experience with C, C++, Objective-C, and Swift, so here are some observations and ideas based on looking at the Superpowered SDK and sample code.
A bridging header lets Swift interface directly with Objective-C, and since Objective-C is a strict superset of C, this implies interfacing with C as well. However, you cannot interface directly with C++, and that's where Objective-C++ comes to the rescue. From what I'm seeing you can mix Objective-C and C++ code in Objective-C++, which allows Objective-C to use C++ classes.
Now on to some specifics.
The bridging header in the SuperpoweredFrequencies example that you looked at introduces a new Objective-C class, Superpowered, which is not part of the library, but of the example, and is implemented in Superpowered.mm. It is an Objective-C++ file, because Superpowered calls some C++ code.
Looking at Superpowered.mm, you will see that it imports Objective-C headers:
#import "SuperpoweredFrequencies-Bridging-Header.h"
#import "SuperpoweredIOSAudioIO.h"
as well as C and C++ headers:
#include "SuperpoweredBandpassFilterbank.h"
#include "SuperpoweredSimple.h"
We could have used import instead of include for C++ code, too, but they are probably using include just to emphasize that it is C++ code. Looking at SuperpoweredBandpassFilterbank.h, we see that SuperpoweredBandpassFilterbank is a C++ class. It is used in Superpowered.mm by the Superpowered Objective-C++ class, see the filters member, which is a pointer to a SuperpoweredBandpassFilterbank object.
In the project you attempted to build, I see where the Superpowered interface is declared in the bridging header, but I don't see an implementation. The failure to #import SuperpoweredRecorder.h is due to SuperpoweredRecorder.h being a C++ header. The #include should be in your Objective-C++ (.mm) file, it's useless in the bridging header, since Swift can't make sense of C++ anyhow.
Hopefully this is helpful. Welcome to the world of C++.
I'm a bit surprised that you would have to provide prototypes of method.
I used Objective C libraries in my Swift project before and I only had to add the header files in my bridging header.
See example from my project. The bridging header contains just that:
// Use this file to import your target's public headers that you would like to expose to Swift.
//
#import "QTouchposeApplication.h"
#import <FBSDKCoreKit/FBSDKCoreKit.h>
#import <FBSDKLoginKit/FBSDKLoginKit.h>
#import <VungleSDK/VungleSDK.h>
Related
I have a question about using C++ header files in Objective-C++ modules in Xcode. Specifically, why can I #include them in source files but not header files?
Here is a specific example.
I'm using Xcode 7.2.1 and have two projects. The first is a C++ framework I package into "myFramework.framework". It exposes "myFramework.h", which in turn pulls in "myLib.h". At the top of "myLib.h" is an "#include <string>".
The second project is an Objective-C iOS app which consumes the above framework. In this project, "myViewController.mm" (Objective-C++ source) has "#import "myFramework/myFramework.h" at the top and makes reference to things defined in that header file.
At this point all is well and good. It builds and runs with no issues.
When I move the "#import myFramework/myFramework.h" line to "myViewController.h", the compile fails because it cannot locate the "" header dependency.
It doesn't matter if I change the file type for "myViewController.h" to Objective-C++ header from plain old "C Header". Either way, Xcode's header search paths don't look for standard C++ headers.
So my main question is why does it behave this way? Why is a #include/#import treated differently just because it's in a header file?
My second question is if there's some way to make Xcode treat the #include/#import the same when it's in the header file instead of the source file?
Thanks much!
Are you sure that you get the error while compiling the myViewController.mm file?
Check if myViewController.h is imported into some other, non ObjC++ file (and that that one is the file that fails to compile).
I suspect the issue with including C++ headers inside other headers is that an Objective-C source file gets to see the C++ header file, which upsets it.
If you have mixed C++/Objective-C++/Objective-C then you are probably better off only exposing a pure Objective-C interface to other modules in the project and include any C++ header files in the Objective-C++ source files only.
Alternatively make everything Objective-C++ and then you don't need to worry about it at all.
Hopefully this answers your second question as well.
I've tried to implement a project which I've found on github.
https://github.com/hossamghareeb/Facebook-POP-Tutorial
While I was implementing the .h and .m files I've got an error which was saying XCode could not find my 'iostream' file.
I'm working in SWIFT, using bridging-headers to use the framework. When I try to build the original project it works, but mine always fails.
How can I add my iostream file?
Thanks in advance!
Swift bridging does not support Objective C++ files. This means that any headers that consume or expose C++ entites (like std::vector; std::iostream) cannot be added to the bridging header.
The POP bridging header contains:
#import "POP.h"
You should really only #import that file in your own bridging header, rather than trying to #import all the .h files.
If you need to consume some of the API that's defined in .mm files that isn't exposed with an Objective C or plain C header, then you'll have to make your own header file that exposes it (and probably a back-end that implements what you've exposed).
The reason why you can use .mm files in a library that's being used by Swift is because all swift uses is the interface to those files - i.e. the .h files, and as long as those files are in plain C or Objective C, then you can make use of the code that is implemented in the .mm file. The .mm files are compiled by Objective C++ compiler (clang++)
Referred Question: Problem when #import C++ Header File in iPhone/iPad Project
Well, my project is relatively huge and cannot solve that either changing ALL or PART OF my project files .m to .mm or changing the ALL or PART OF file types in File Inspector.
That is because both my colleagues and library authors DOES NOT follow the C++ standard strictly, such as assigning void* to int* and other various violations. Objective C would allow these and just gives warnings.
The C++ header file I want to #import is a library. It uses keyword namespace in its header, while its implementation is in an .a assembly file. That means it is nearly impossible to hack them. Besides that, my project also includes other libraries that are compatible only with Objective C.
Does anyone know how to solve this?
The ways I could imagine is as follows:
Find an alternative for namespace, but still I want to write
codes like QCAR::Renderer in my project.
Tell the compiler to recognized C++ header(Well, that might not be
possible)
EDIT
#ifdef __cplusplus
# include MyCPPHeader.h
#endif
If I use that, would MyCPPHeader.h really get included in an Objective-C environment? I guess not. And that's against the principles of not hacking libraries.
EDIT
Even I changed these .mm files to include that C++ Header, i would get an link error saying Undefined symbols for architecture armv7:. This happens when my .mm files including .h headers in other libraries.
I have solved this a year ago, but for other people who are looking for an answer, here is the solution.
Say the C++ style header is named cpp.h. In my project, I never #import "cpp.h". I wrote a C style header, named c.h, as a wrapper header for cpp.h. Then I wrote a C++ implementation source file, named c.mm to implement the function define in c.h by calling functions in cpp.h. If I want to call functions in cpp.h, I #import c.h and use the wrapper function instead.
Below is the explanation in a possibly clearer way:
cpp.h C++ style header file using the namespace, its implementation is in assembly code so it is hard to change
c.h C style header as the wrapper for cpp.h
c.mm C++ implementation implements functions in c.h by calling functions in cpp.h
#import "c.h" to use the wrapper functions
I'm getting include not found compile error in XCode. I have an iOS app project that i use Objective-c and c++ as mix.
Initially, i created one .h file and one .cpp file in my ios project. Then, I renamed the .cpp file to .mm file.
Here is my .h file;
TestLog.h
#ifndef CalculatorDemo_TestLog_h
#define CalculatorDemo_TestLog_h
#include <string>
using namespace std;
class TestLog
{
private:
string logString;
public:
void Log(string logMessage);
};
#endif
TestLog.mm
#include "TestLog.h"
void TestLog::Log(string logMessage)
{
//this->logString->append(logMessage);
}
What am I missing? Do I need to add std c++ library to my targetS? Something related to Search Header Paths?
I just need to use string type.
Thanks much for in advance
select project -> build setting -> apple LLVM compiler 5.1 -> language
In Compile Sources As change to Objective-C++
There's a quirk in XCode. I noticed it in 7.3. Most projects recognize .mm files and the STL, while one project I had did not. The fix was that I had to click on the top-left project icon, then click Targets > Build Phases > Link Binary with Libraries > and add in AppKit.framework. Next, I had to click Targets > Build Settings > search on "Compile Sources", and set it to "Objective C++" on all possible columns. Then, do a Clean and then a Build from the Product menu. This compiled properly then. Then, go back to that Compile Sources again and set it back to "According to File Type" on all possible columns. Then, click Build from the Product menu again. At that point, it compiled properly and allowed me to utilize the "according to file type" option, which I like better.
Oh, and if doing Cocoa stuff, don't forget to add the following header in your files:
#import <Cocoa/Cocoa.h>
And if doing command line stuff, don't forget to add the following instead of the Cocoa header:
#import <Foundation/Foundation.h>
i believe you need to include the whole path to the library. similarly to say "foundation" & "uiview" frameworks.
#import <Foundation/Foundation.h>
or
#import <UIKit/UIKit.h>
and yes, make sure you add the library to your target.
So I was having this issue with the Cocoapods library Bypass and none of these solutions did anything. The problem was with a file which Cocoapods creates called an umbrella header. This is located in <POD_NAME>/Support Files/<POD_NAME>-umbrella.h. Delete it, and it should build just fine.
Now for the explanation of why this is necessary: the umbrella header is mixing both C++ and Objective-C code directly in a header which is a big no-no apparently and ends up completely breaking the C++ imports. By removing it (which seems to have no effect?) this conflicting import which Cocoapods unknowingly created will go away.
Ran into this with xcode 12.4 with a project that is objective-c, but where I need one C++ modul. Solution: wrap the contents of the .h file in:
#if defined __cplusplus
declarations
#endif
Apparently xcode is not good at detecting a mix of sources.
see Expected ; after top level declarator, error in xcode
This often happens when Xcode doesn't understand that a C++ header file you've imported into Objective-C is actually for C++ code.
So you can solve this problem by finding the Objective-C file that imports C++ code, and simply change its extension from .m to .mm
I made an Objective-C project for the iPhone. I had only one cpp class, the soundEngine taken from some Apple demo. Now I'm trying to merge OpenFeint which is coded in Objective-C++. I dropped in the code, by simply dragging the files and just tick "Call C++ default ctors/dtors in Objective-C" in Project Settings. I am not even referring to it from my code. When I hit Build, my Objective-C code cannot find the methods of the cpp file.
All the class files compile, including OpenFeint's, but in the linking stage it says several of these errors:
"_SoundEngine_SetDisabled", referenced from: someClass.o
Note that it is adding an underscore in front of the methods when it's reporting these linking errors.
P.S. I know that for OpenFeint first thing one should do is convert the files to .mm but if possible I don't want to go down that road at this stage of development. I was going to try create a wrapper Objective-C++ class for it. I read someone managed to do that.
If you're saying you have Objective-C++ files that are not .mm files, then they're not being read as Objective-C++ unless you've done something special to make it so. .mm is the extension for Objective-C++ files. That's why you've been advised to use it.
but in the linking stage it says several of these errors: "_SoundEngine_SetDisabled", referenced from: someClass.o
There's no name mangling on that method. Is it declared as extern "C" in a header somewhere but defined as a C++ method/function.