Access SpringBoardServices.h method in objective-c? - ios

I downloaded SpringBoardServices.h file given in SpringBoardServices and added it to my project. But how to access one of the method present inside SpringBoardServices.h file. I am trying to call BOOL SBSProcessIDForDisplayIdentifier(CFStringRef identifier, pid_t *pid); this method present inside SpringBoardServices.h from MyClass.m file. How to call above method from my .m file?
I used below approach, but it is returning null.
Class myclass = NSClassFromString(#"SpringBoardServices");
NSLog(#" myclass %#", myclass); //null
id myobj = [[myclass alloc] init];
I downloaded SpringBoardServices.h file from this link.

There are couple of methods to access C methods from private framework:
Method 1:
Link a private framework (similar to the way how you link public framework)
Include .h file
Do a call:
SBSProcessIDForDisplayIdentifier(...)
Method 2:
Load framework in runtime using dlopen
Find a method using dlsym
Do a call
BTW. This is applicable to C method's and second method won't work for ObjectiveC methods.

Related

Swift class in ObjC Project : Receiver 'MySwiftClass' for class message is a forward declaration

After spending a few hours to integrate swift files successfully to my Objective-C based iOS project, I face the next challenge now :
In one of my Objective-C class header (Say, MyObjCClass.h), I do the forward declaration for MySwiftClass.
In the respective .m file, I define an instance of MySwiftClass _swiftClassInstance.
In the init method of MyObjCClass, I try to instantiate it as follows :
_swiftClassInstance = [[MySwiftClass alloc] init];
When I compile the code, I get 2 errors:
Receiver 'MySwiftClass' for class message is a forward declaration
Receiver type 'MySwiftClass' for instance message is a forward declaration
I have already done following :
Imported MyProject-Swift.h in the MyObjCClass.m file.
Marked the swift class with #objc and open
So, what can be the reason for the issue?

Objective C++: Call Objective C method from C++

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.

How to access an internal Swift class in Objective-C within the same framework?

Working on a mixed framework. imported inside the Obj-C file but the internal classes are not visible, only the public ones.
The documentation clearly states the internal clasees should be available between Swift and Obj-C:
Importing Swift into Objective-C To import a set of Swift files in the same framework target as your Objective-C code, you don’t
need to import anything into the umbrella header for the framework.
Instead, import the Xcode-generated header file for your Swift code
into any Objective-C .m file you want to use your Swift code from.
Because the generated header for a framework target is part of the
framework’s public interface, only declarations marked with the public
modifier appear in the generated header for a framework target. You
can still use Swift methods and properties that are marked with the
internal modifier from within the Objective-C part of your framework,
as long they are declared within a class that inherits from an
Objective-C class. For more information on access-level modifiers, see
Access Control in The Swift Programming Language (Swift 2).
Code Sample (Create a new project with a framework)
// SwiftObject.swift
public class SwiftObject: NSObject {
public class func doSomething() {}
}
internal class YetAnotherSwiftObject: NSObject {
internal class func doSomething() {}
}
// SomeObject.m file
#implementation SomeObject
- (void)someMethod {
[SwiftObject doSomething];
}
- (void)someOtherMethod {
[YetAnotherSwiftObject doSomething]; // Use of undeclared identifier
}
#end
As indicated in the docs, declarations marked with internal modifier don't appear in the generated header, so the compiler does not know about them and thus complaints. Of course, you could send messages using performSelector approach, but that's not convenient and bug-prone. We just need to help the compiler know that those declarations are there.
First, we need to use #objc attribute variant that allows you to specify name for your symbol in Objective-C:
// SwiftObject.swift
#objc(SWIFTYetAnotherSwiftObject)
internal class YetAnotherSwiftObject: NSObject {
internal class func doSomething() {}
}
And then you just need to create #interface declaration with the methods you want to use in your code - so the compiler will be happy, and also apply SWIFT_CLASS macro with the symbol name you've specified earlier - so the linker would pick the actual implementation:
// SomeObject.m file
SWIFT_CLASS("SWIFTYetAnotherSwiftObject")
#interface YetAnotherSwiftObject : NSObject
+ (void)doSomething;
#end
#implementation SomeObject
- (void)someOtherMethod {
[YetAnotherSwiftObject doSomething]; // Should work now !!!
}
#end
I've used the interface declaration in .m file just for clarity, the better option would be to combine such declarations in .h file, and include it.
By declaring methods in that interface we're making a promise to compiler, and it won't complain if you'll put there a method that does not exist (or with wrong signature, etc.) Obviously, you'll crash in runtime in that case - so be cautious.
For me it just worked by checking: "Allow app extension API only". You find it by going to the project setting, select your target and then it is in the General tab under Deployment Info.
Can someone explain to me, why this does solve the problem?
While the above solution works (https://stackoverflow.com/a/33159964/5945317), it seems overly complicated and unintuitive:
Complicated, because it seems to add more things than necessary – I will provide a smoother solution below.
Unintuitive, because the objc macro SWIFT_CLASS resolves to SWIFT_RUNTIME_NAME, and the provided value is not actually the runtime name – nor is the objc class name in the header matching the Swift attribute param in #objc. Still, surprisingly, the solution works – but to me it is not clear why.
Here is what we have tested in our own project, and believe to be the better solution (using the example above):
// YetAnotherSwiftObject.swift
#objc(OBJCPREFIXYetAnotherSwiftObject)
internal class YetAnotherSwiftObject: NSObject {
#objc internal class func doSomething() {}
}
// OBJCPREFIXYetAnotherSwiftObject.h
#interface OBJCPREFIXYetAnotherSwiftObject : NSObject
+ (void)doSomething;
#end
That's it. The interface looks like a regular objc interface. This gives the added benefit that you can include it in other header files (which you cannot do if you use the SWIFT_CLASS macro, as it comes from the autogenerated Swift header file, which in turn you cannot include in an objc header, due to circular dependency).
On the Swift side, the only thing relevant is that you provide the class with the proper objc name. Mind that I only used the name prefix for language consistency – you can even just use YetAnotherSwiftObject everywhere (i.e., in the objc header and in the #objc attribute in Swift – but you need to keep this attribute with explicit naming in any case, and need to keep it consistent with the class name in the header).
This also makes your life easier if you're in the process of converting your objc framework step by step to Swift. You just keep the objc header as before, and now provide the implementation in Swift.
Methods and properties that are marked with the internal modifier and declared within a class that inherits from an Objective-C class are accessible to the Objective-C runtime.
so let's make use of that:
class MyInternalClass: NSObject {
#objc var internalProperty = 42
}
#interface MyPublicClass()
#end
#implementation MyPublicClass
+ (void) printValue {
Class myInternalClass = NSClassFromString(#"MyPackageNameIfAny.MyInternalClass");
id myInternalClassInstance = [myInternalClass new];
int value = [myInternalClassInstance performSelector:#selector(internalProperty)];
NSLog(#"Value is %d ", value); // "value is 42"
}
#end
Using the SWIFT_CLASS macro and #objc class attribute could easily lead to errors when archiving. This approach is safer.

How to check if class is available or not in Static lib?

I will try to explain my problem.
I am creating two libs home.a & room.a independently. From home lib I have calls to the functions which I implemented in room.a
I am want two use this two libs in one project, the case is I want to keep room.a as optional. If I don't add room.a in project, I am not able to build project.
Error is:
Undefined symbols for architecture
"_RoomViewController", referenced from:
-[ParentViewController openView:] in home.a
Here RoomViewController is class from room.a & ParentViewController is class from home.a
I want to add condition in code home.a to check RoomViewController is present then create a object of RoomViewController.
Please suggest me a way for to do this.
Thanks in advance.
If you want the project to compile without errors, you need to add a header file that declares the RoomViewController class. For instance, write a RoomViewController+Private.h file.
#interface RoomViewController: UIViewController
#end
#interface RoomViewController()
//List of methods you want to use
- (void)methodA;
- (void)methodB;
#end
To check whether you linked the library room.a at runtime, you need to do the following:
if ([RoomViewController class]) {
// class exists
RoomViewController *instance = [[RoomViewController alloc] init];
} else {
// class doesn't exist
}

How to call Objective-C "self" from C method [duplicate]

This question already has answers here:
Pass instance method as function pointer to C Library
(1 answer)
How do I give C function a pointer to 'self' (calling obj) in objective-c?
(2 answers)
Closed 9 years ago.
I have Objective-C class in my iOS project that implements Objective-C and C code in the same class. I changed the extension to .mm and this part goes well. Now I want to set a C method that will call the Objective-C method in the same class. The problem I get is when I am trying to call self from the C method.
Here is the code :
void SetNotificationListeners(){
[self fireSpeechRecognition];
}
the error is :
Use of undeclared identifier 'self'
how can I manage this?
You have to pass the instance pointer to the C function:
void SetNotificationListeners(void *uData)
{
MyClass *obj = (__bridge MyClass *)(uData);
[obj fireSpeechRecognition];
}
- (void)myMethod
{
// Call C function from Objective-C method:
myFunction((__bridge void *)(self));
}
(The "brigde" stuff is needed only if you compile with ARC.)
Either give self as an argument to the function call:
void SetNotificationListeners(void *myObj){
[(MyClass*)myObj fireSpeechRecognition];
}
//in objC
SetNotificationListeners(self);
or have a global variable that holds reference
//global variable
static MyClass *myObj;
//in obj c
myObj = self;
SetNotificationListeners(); //use myObj instead of self in function
The first is better in my opinion.
You don’t have to change the file extension. Objective-C is a superset of C, which means you can use plain C in your Objective-C files as you please.
When you write an implementation of an Objective-C method, that method always executes in context of some particular instance, that’s the self part. You get the self in an Objective-C method automagically, but behind the scenes it’s just passed as an argument to the method, see obc_msgsend.
Your plain C function is not a part of the class (plain C functions never are), therefore there’s no instance associated with it when you call it, there’s no implicit self. If you want the function to call some instance, you have to pass the pointer to that instance explicitly. For example some of the plain C APIs have a “context” pointer you can pass when registering for a callback. See the neighboring answers for examples of this.
In Objective-C methods there are two parameters that are implicitly passed into each method, which are self and _cmd. This is why you can access self from within a method.
You could just pass self as an argument to your c function when calling from an Objective-C method, but with that trivial example I'm not sure why you wouldn't just use a method.
You do not need to change the file extension to .mm unless you are using Objective-C++

Resources