I'm trying to use the peertalk framework which has no documentation.
On their obj-c example they use the INADDR_LOOPBACK macro, and example is working.
But when i try to do the same in swift the system throw me an unresolved identifier error.
Anyone knows how to fix it?
http://www.gnu.org/software/libc/manual/html_node/Host-Address-Data-Type.html
Update for Swift 3: As of Swift 3, INADDR_LOOPBACK
is imported into Swift. Therefore it suffices to add
#include <netinet/in.h>
to the bridging header file, but a custom definition is not
needed anymore.
Old answer: For some reason, the macro definition
#define INADDR_LOOPBACK (u_int32_t)0x7f000001
from <netinet/in.h> is not imported into Swift.
The problem might be the (u_int32_t) cast, because
other macros like
#define INADDR_NONE 0xffffffff /* -1 return */
are imported.
One solution is to define
let INADDR_LOOPBACK = UInt32(0x7f000001)
in your Swift code. Alternatively, add
#include <netinet/in.h>
const uint32_t kInAddrLoopback = INADDR_LOOPBACK;
to the bridging header file and use kInAddrLoopback in the Swift code.
This is less error-prone because you don't have to repeat the constant.
From the Apple documentation.
Declare simple macros as global constants, and translate complex
macros into functions.
Related
I have a game in Objective-C and I have constant in it declared like this, in file GameplayConstants.h:
#ifndef GameplayConstants_h
#define GameplayConstants_h
static float REGULAR_TIME_PER_FRAME = 0.1f;
#endif /* GameplayConstants_h */
I am converting game to swift, so I want to convert one by one file to swift. In particular, I want this constant (REGULAR_TIME_PER_FRAME) converted to a swift file, to a constant variable in a swift file GameplayConstants.swift (rather than in the GameplayConstants.h file which it currently sits in now). What should I do? I set the defines module in configuration file to YES, and I included the file (with line include GameplayConstants.swift), but I have various errors. At the moment, error is:
"missing #end"
in HeroAnimationhelper.m file, which has code (partial code displayed):
#import "HeroAnimationHelper.h"
#import "HeroConstants.h"
#import "dealer-Swift.h"
#implementation HeroAnimationHelper
//#include "GameplayConstants.h"
#include "GameplayConstants.swift"
As you see, I'm replacing the original .h file with .swift file.
What else do I need to do to use swift constants in a objective-c class?
my objective c code is not called because custom flag defined in settings is not visible here. Why? How can I define the same for objc?
For Swift it is enough to define Custom Flags as:
-DMYFLAG
for Objective-C you need to define Preprocessor Macros:
MYFLAG=1
Then in both Swift and ObjC files you can use it like:
#if MYFLAG
//code
#endif
OBJ-C ONLY...
That is,
An ObjC app imports ObjC static lib A.
Static lib A imports static lib B.
Static lib A has functions that call functions within lib B.
The app only calls functions in lib A and does not call functions in lib B.
Can I assume that lib A or B can be either Obj-C or Swift?
IE. Can an ObjC app import an ObjC-or-Swift static lib A that itself imports a second ObjC-or-Swift static lib B? (yes, 4 use case permutations)
the git repository https://github.com/CombineCppSwiftObjcInStaticLib i created for you is showing this..
your initial #objc func run_central() in BLE_central.swift is exposed, which triggers the precompiler to generate objc compatible headers (bridge) which then again makes it possible to call the function from a method inside .mm(objc++) or .m(objc) when this generated header is imported.
In fact Hub_lib inside the repo is a static ObjC++ lib mixed with Swift. It would work the other way around also. The headers are the key for success here. If you can provide some objc or c or c++ header to swift functions it becomes compatible and wise versa. I mean in general, thats the idea of headers. If you don't have headers, that does not mean you can not call some external stuff, it just means you would call it blind. A proper IDE will complain before you even try to do this evil stuff, unknown entry points aka unknown symbols etc.. So you go for a proper header - always.
To properly combine swift with other languages its good to know there are always two ways of bridging.
In case of Objective-C (and also Objective-C++) it is
Bridging into Swift (projectname-Bridging-Header.h),
and Bridging out of Swift (expose with #objc to trigger automatically internal generation of projectname-Swift.h file. So this header is "invisible" in the file browser on the left side. Nor will you find it in the repo as file, it is named by modulename which is the project-name). The last mentioned header you could even write manually yourself, with lots of troublesome back-draws.
Hint: Executable code is executable code. No matter what language, as far it is compiled for the right device architecture and has symbols to call and you know what to do with the data returned.
Another Hint: there is a way to handle C pointers in swift see docu which become swift datatypes which you can use to go the other way and declare functions to return those from swift.
And direct use of C in Swift is also possible. The compiler considers if you explicit mark some code as C. extern "C" { /* code */ } will cause the C++ compiler to remember, this is still C++ code to compile the function in such a way, it can be called from C (and Swift)
//Example.hpp //no target membership
#ifdef __cplusplus
#include <stdio.h>
class Example {
private:
const char * _name;
public:
Example(const char *name);
~Example(void);
int getLen(void);
};
#endif
There should be an Example.cpp and don't forget to tell Xcode you deal with c++ #ifdef __cplusplus + #endif
//Example.cpp //has target membership
#include "Example.hpp"
#ifdef __cplusplus
#include <stdio.h>
#include <string>
//code implementation according to example.hpp
Example::Example(const char *name) {
_name = name;
}
int Example::getLen() {
return (int)strlen(_name);
}
#endif
//ExampleWrapper.cpp //has target membership
#include "Example.hpp" //c++ header file
extern "C" int myCppFunction(const char *s)
{
// Create an instance of Example, defined in the library
// and call getLen() on it, return result.
return Example(s).getLen();
}
So this function needs to be declared in the bridging header to make use of it.
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
// for extern "C" functions declare them one by one here
// as implemented in ExampleWrapper.cpp
// becomes "func myCppFunction(_ s: UnsafePointer<Int8>!) -> Int32" in swift
int myCppFunction(const char * s);
and then call from swift..
os_log("The result from C++ is %u", myCppFunction("12345"))
So in fact, yes. Integrating a static lib A that calls static lib B in App is possible. Happy compiling as long you offer some header for each part that needs to know what is inside the head of the other lib. That is true for Apps as it is true for libs and frameworks under each other.
Edit here some important stuff to read about Swift Package Manager C support https://github.com/apple/swift-evolution/blob/master/proposals/0038-swiftpm-c-language-targets.md
As long as the libraries export Objective-C compatible symbols, it doesn't matter if they're written in Objective-C, or Swift, or C++, or any other compiled language.
And we know that the Swift compiler exports Objective-C compatible symbols for all declarations that are marked with #objc (either explicitly or implicitly).
From a consumer perspective it doesn't matter which language generated the libraries, as long as the Objective-C compiler/linker can consume the symbols exported by those libraries.
This question already has an answer here:
Force Header Files to Compile as C++ in Xcode
(1 answer)
Closed 2 years ago.
I'm trying to use a 3rd party sample code as part of my Objective-C application.
However, when trying to compile my project I get a lot of compiler errors.
The objc syntax that is used in the sample is quite strange and I believe that it is compiled as something else within the project.
For example, as part of the header file the struct definition has default values:
File.h
struct Options
{
int count = 100;
}
...
In their project, the above header file would compile just fine, but when I try to compile it I see an Xcode error:
Expected ';' at end of declaration list
I'm not an objective-c expert, but from what I've read and also found as part of other posts data types cannot have default values, but somehow it compiles fine in the Xcode sample app.
Please let me know if you need more info or other examples of what would compile fine in their project and doesn't work when I copy and paste the code into mine.
Edit:
Force Header Files to Compile as C++ in Xcode
Individually header files doesn't compiled. Compiled source files where they included. If you include them in .c they will be compiled like C, if in .m - like Objective-c, if in .cpp - like C++, if in .mm - like Objective-C++.
My issue was that I was using this header file into a .m file which compiles it to an Objective-C standard. When I change the extension to .mm everything worked fine.
When you think of objective-C as actually being C its more clear why defaults are not set in .h files
This does not apply to the rules of default sizes which are needed when no flexible memory allocation for a data type is available by default, like for (as is) most data types in C.
Even this two sentences already show the difficulty to distinguish what is meant with "default".
Which is why you end up with definition of initiation processes and functions to declare what exactly is "default" in the other file.
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
int count;
} Options;
typedef struct {
int foo;
Options bar[100];
} Foo;
struct Bar {
Foo lotsof;
}
void MyInitiationFunction(Bar *b);
// definition of MyInitiationFunction in .m/.c file
#ifdef __cplusplus
}
#endif
but there is the concept of enum that can trick your mind where defined enumeration default states are what you build some stuff on, which is not a value.
I'm trying to configure cocoalumberjack and when I've added ddLogLevel set to LOG_LEVEL_VERBOSE XCode throws "use of undeclared identifier" error. Why is that? How to avoid?
This question indicates that clearing DerivedData and restarting Xcode solves this kind of error.
However you should not include variables in the pre-compiled header as it will be included in every source file and prefix files are somewhat complicated compared to normal header files.
Better is to have use a Constants.h file which contains:
extern int ddLogLevel;
and #import that into your prefix file.
Then create an Constants.m with:
int ddLogLevel =
#ifdef DEBUG
LOG_LEVEL_VERBOSE;
#else
LOG_LEVEL_ERROR;
#endif
This way there is only one instance of ddLogLevel and it can be easily changed at runtime if necessary.
See this question for hints about prefix file best practices.
What solved it for me was changing #import <CocoaLumberjack/CocoaLumberjack.h> to #import CocoaLumberjack;, when using Xcode 8.0 for an Objective-C project.
Droppy’s post is correct and I recommend doing that, but I would like to address the question directly. There is a flaw in your code that may be resulting in the error.
LOG_LEVEL_VERBOSE is defined in DDLog.h. Your header file only imports DDLog.h if __OBJC__ is defined, but uses LOG_LEVEL_VERBOSE without this condition. Therefore if __OBJC__ is not defined, LOG_LEVEL_VERBOSE will be undefined.
Why would __OBJC__ not be defined? The prefix header is prepended to C, C++, Objective-C and Objective-C++ files. Since __OBJC__ is only defined for the latter two, if there are any C or C++ files in your project then the error will occur.
Knowing this, it is clear the ddLogLevel definition should be inside the #ifdef __OBJC__ check. However, you should do what Droppy said, and also make sure all Objective-C imports go inside the check.
For people who use "CocoaLumberjack 2.X" and still facing same issue after pod update, please try to import "DDLegacyMacros.h".
For prefix file users, try something like this :
#ifdef __OBJC__
...
...
#import <DDTTYLogger.h>
#import <DDLog.h>
#import <DDLegacyMacros.h>
#endif
Hope this helps someone else.