I'm trying to assign a function to the AURenderCallback inputProc
int setupRemoteIO(audio unit etc){
inProc.inputProc = playerCallback
}
but it says that playerCallback is not declared in this scope although playerCallback is present in the same file and class as setupRemoteIO.
The player callback is like this
static OSStatus playerCallback(void *inRefCon etc)
What could be the problem?
In C, you need to declare a function before its first use, i.e. higher up in the file than the point where you try to use the function. That's why include files are usually clustered at the top of a file; all of the symbols declared in the headers will be available throughout the code in the including file.
In this case, that means the declaration of your callback:
static OSStatus playerCallback(void *inRefCon etc);
must appear before your setupRemoteIO() function so that the compiler knows the function exists when you come to use it.
As you're on iOS, I'll also make the point that in recent compilers this restriction doesn't apply to Objective-C methods. It used to: you could only use method selectors that had already been seen. But in newer versions of Clang an Objective-C method can make use of a selector declared later in the same file without error.
Related
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.
I have the following method section
- (NSString*) GetPathForFolder:(int)folder inDomains:(int) domains {
id cls = objc_getClass("NSFileManager");
SEL defaultManagerSelector = #selector(defaultManager);
SEL urlsForDirectoryInDomainsSelector = #selector(URLsForDirectory:inDomains:);
id fileMangerHandle = objc_msgSend(cls, defaultManagerSelector);
//NSArray<NSURL *>* notUsedArray = [fileMangerHandle URLsForDirectory:folder inDomains:domains];
NSArray<NSURL *>* resultArray = (NSArray<NSURL *>*) objc_msgSend(fileMangerHandle, urlsForDirectoryInDomainsSelector, folder, domains);
return [resultArray lastObject].absoluteString;
}
Calling this method with [self GetPathForFolder:5 inDomains:1]
returns file:///Applications/ which is wrong
The moment I uncomment the NSArray<NSURL *>* notUsedArray.. line I get a different and correct value which just happens to be the same as the one from
What does the objective-c version of the call do that I'm not doing in my C version?
Update:
I'm using objc_msgSend because this method will eventually be called from C# but it's just easier to first try it in objective-c and than start worrying about the interop part.
I was using sel_registerName because when running this inside of C#, I'm going to have to do my own registration.
More about Interop between C# and objective-c here. And also a java version of what I'm trying to understand is here.
You can’t use objc_msgSend like this, it is not a variadic function, even though it’s prototype suggests it. The compiler needs to use the same calling convention that the method is expecting. For this it needs to know the exact types of all parameters. You can tell it by casting objc_msgSend to a function pointer type with the correct parameters.
So for this case you would use something like this:
typedef NSArray<NSURL *> *(*UrlsForDirectoryType)(id, SEL, NSUInteger, NSUIteger);
NSArray<NSURL *>* resultArray = ((UrlsForDirectoryType)objc_msgSend)(fileMangerHandle, urlsForDirectoryInDomainsSelector, folder, domains);
The typedef is optional, of course, but then that makes the whole thing even harder to read.
To expose this to a different programming language you could also write regular C functions in Objective-C and call those. This is much easier to do than dealing with the runtime directly.
I'm using NSURLSession to connect to a database. I have this already implemented in C++ for Windows and am trying to get it working on iOS also. I have a .h file derived from a base C++ class that is the header for my .mm file. If I'm correct I have to implement all the functions in my .h file in C++. However NSURLSession is an Objective-C function. How do I call an Objective-C method from my C++ function?
I have a C++ function called Connect() where I make a C++ object m_Delegate that has an alloc and init.
this->m_Delegate = [[PrivateNSURLSessionDelegate alloc] initWihParent:this];
//where PrivateNSURLSessionDelegate is the name of my interface.
That interface has -(bool)NSConnect (with implementation in the #implementation) which I'm trying to call from:
void Connect()
{
[PrivateNSURLSessionDelegate NSConnect];
//This however gives me the error: +[PrivateNSRLSessionDelegate NSConnect]: unrecongnized selector sent to class
}
I also tried it using my C++ object
void Connect()
{
[m_Delegate NSConnect];
//This gives me a error that is unrecognized selector sent to instance
}
Is there a better way to do this? I basically want to ask the Objective-C to do all the NSURL stuff and send just the data back to the C++.
I'm completely new to Objective-C so any and all help would be greatly appreciated! Thanks!
-(bool)NSConnect
Here the - indicates it is an instance method. Conversely + would indicate a class method.
That being said, [PrivateNSURLSessionDelegate NSConnect]; calls a class method, since you call it on the interface PrivateNSURLSessionDelegate.
However, this is not defined as it is defined as NSConnect is defined as an instance method (btw the convention is that (instance) methods always start with a lowercase).
[m_Delegate NSConnect];
Does however call the instance method. You should define -(bool)NSConnect in the header file of PrivateNSURLSessionDelegate, not above the #implementation in the implementation file, that makes in a private method and thus inaccessible.
There is Objective-C, which is a superset of C, and Objective-C++, which is a superset of C++. Objective-C++ source code files have a .mm suffix, where Objective-C would have a .m suffix.
You cannot call Objective-C from C++. You can however call Objective-C from Objective-C++, and you can write your usual C++ classes in Objective-C++ as well.
Here is the code
[EvoScrollBarTagView initWithScrollView:self.listTableView
withTagView:[TagView new]
didScroll:
^(id scrollBarTagView, TagView *tagView, CGFloat offset) {
[scrollBarTagView showTagViewAnimation];
........
And my confusion is why the scrollBarTagView(type-of id) can call the method or properties in my EvoScrollBarTagView.h . the parameter scrollBarTagViews type is id, not declared as the EvoScrollBarTagViews instance object, can someone tell me why , Thank you very much...
As mentioned in Objective-C is a dynamic language:
The id type defines a generic object pointer. It’s possible to use id
when declaring a variable, but you lose compile-time information about
the object.
So it doesn't mean that scrollBarTagView can call any method, all it means that it will compile successfully. If the referenced method is not implemented, the app will crash during runtime.
That's part of the point of id -- dynamic typing. You can try to send any message (that the compiler knows about at this point in the code) to an expression of type id without any compiler error or warning.
I'm having a hard time making sense of the Apple ARM64 Function Calling Conventions doc and ARM Procedure Call Standard.
When a function is called, I understand that $r0 is self, and $r2 appears to be the first function argument.
What is in $x1?
Does the stack pointer refer to the first argument beyond four?
You want to read the "The Base Procedure Call Standard" chapter of the AAPCS64, section 'Subroutine Calls'; their register naming convention uses "r0..r30" where lldb uses "x0..x30". x1 is the second argument register. x0 is the first. The arm64 iOS ABI's biggest difference from AAPCS64 is in how variadic functions (printf etc) are called. The apple doc you linked to details the exact difference.
lldb provides register alias names for armv7/arm64/x86_64, $argi, to refer to the ith argument. $arg1, $arg2, etc. (Arguments are passed on the stack on i386 so the aliases aren't defined there) I'd recommend using these convenience names and not worrying about the details of the architecture, if possible.
NB these argument passing register contents are only valid at the start of the function. They're usually saved on the stack or copied into other registers -- the registers will be reused/overwritten as soon as another function call is made.
According to the Mike Ash blog post here, writing a method like this:
- (int)foo:(NSString *)str { ...
Gets translated to a function like this:
int SomeClass_method_foo_(SomeClass *self, SEL _cmd, NSString *str) { ...
So the argument in $x1 is a pointer to the the selector, which is basically just a string holding the method name.