Does Swift support reflection?
Looks like there's the start of some reflection support:
class Fruit {
var name="Apple"
}
reflect(Fruit()).count // 1
reflect(Fruit())[0].0 // "name"
reflect(Fruit())[0].1.summary // "Apple"
From mchambers gist, here:
https://gist.github.com/mchambers/fb9da554898dae3e54f2
(Reflection) Calling A Method With Parameters By Function Name In Swift
First of all, as you noted Swift doesn't have full reflection capabilities and rely on the coexisting ObjC to provide these features.
So even if you can write pure Swift code, you will need Solution
to be a subclass of NSObject
(or implement NSObjectProtocol
).
Playground sample:
class Solution: NSObject {
@objc func functionName(greeting: String, name: String) {
print(greeting, name)
}
}
let solutionInstance = Solution() as NSObject
let selector = #selector(Solution.functionName)
if solutionInstance.responds(to: selector) {
solutionInstance.perform(selector, with: "Hello", with: "solution")
}
There are other points of concern here:
- Swift's
perform
is limited to 2 parameters - you need to have the exact signature of the method (#selector here)
If you can stick an array in the first parameters, and alway have the same signature then you're done.
But if you really need to go further you have no choice than to go with ObjC, which doesn't work in Playground.
You could create a Driver.m file of the like:
#import
#import
id call (NSObject *callOn, NSString *callMethod, NSArray *callParameters)
{
void *result = NULL;
unsigned int index, count;
Method *methods = class_copyMethodList(callOn.class, &count);
for (index = 0; index < count; ++index)
{
Method method = methods[index];
struct objc_method_description *description = method_getDescription(method);
NSString *name = [NSString stringWithUTF8String:sel_getName(description->name)];
if ([name isEqualToString:callMethod])
{
NSMethodSignature *signature = [NSMethodSignature signatureWithObjCTypes:description->types];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
NSObject *parameters[callParameters.count];
for (int p = 0; p < callParameters.count; ++p) {
parameters[p] = [callParameters objectAtIndex:p];
[invocation setArgument:¶meters[p] atIndex:p + 2]; // 0 is self 1 is SEL
}
[invocation setTarget:callOn];
[invocation setSelector:description->name];
[invocation invoke];
[invocation getReturnValue:&result];
break;
}
}
free(methods);
return (__bridge id)result;
}
Add it to a bridging-header (for Swift to know about what is in ObjC):
// YourProjectName-Bridging-Header.h
id call (NSObject *callOn, NSString *callMethod, NSArray *callParameters);
And call it with a Solution.swift like this:
import Foundation
class Solution: NSObject {
override init() {
super.init()
// this should go in Driver.swift
let result = call(self, "functionNameWithGreeting:name:", ["Hello", "solution"])
print(result as Any)
}
@objc
func functionName(greeting: String, name: String) -> String {
print(greeting, name)
return "return"
}
}
output:
Hello solution
Optional(return)
Edit: compilation
To compile both ObjC and Swift on the command line you can first compile ObjC to an object file:
$ cc -O -c YouObjCFile.m
Then compile your Swift project with the bridging header and the object file:
$ swiftc -import-objc-header ../Your-Bridging-Header.h YouObjCFile.o AllYourSwiftFiles.swift -o program
working sample
Reflection with Swift - Get functions name of a class
Reflection in Swift is very limited compared to the hackeries available in Objective-C. Having said that, the Objective-C runtime functions are still available in Swift. You can sneak your class into the Objective-C world by making it inherit from NSObject
:
class MyClass: NSObject {
func f1() {}
func f2() {}
func f3() {}
}
let myClass = MyClass.self
var methodCount: UInt32 = 0
let methodList = class_copyMethodList(myClass, &methodCount)
for i in 0.. let selName = sel_getName(method_getName(methodList[i]))
let methodName = String(CString: selName, encoding: NSUTF8StringEncoding)!
print(methodName)
}
This will give you 4 methods: f1 ... f3
and init
.
Swift: Mirror(reflecting: self) too slow?
Not only is that slow, it's also not a good idea: mirroring is for debug introspection only. You should instead construct the dictionary yourself. This ensures that you have the flexibility to store all the data in exactly the right way, and also decouples your Swift property names from the keys of the dictionary you're generating.
class SomeClass {
var someString = "Hello, stackoverflow"
var someInt = 42 // The answer to life, the universe and everything
var someBool = true
func objectToDict() -> [String: AnyObject] {
return ["someString": someString, "someInt": someInt, "someBool": someBool]
}
}
Related Topics
Determine on Iphone If User Has Enabled Push Notifications
Swift Saving and Retrieving Custom Object from Userdefaults
How to Put Buttons Over Uitableview Which Won't Scroll With Table in Ios
How to Detect the End of Loading of Uitableview
How to Detect If App Is Being Built For Device or Simulator in Swift
Swrevealviewcontroller Without Using Navigationcontroller
Core Data and iOS 7: Different Behavior of Persistent Store
Best Way to Add License Section to iOS Settings Bundle
Uiactivityviewcontroller Crashing on iOS 8 Ipads
How to Play Audio in Background With Swift
Create Uiimage With Solid Color in Swift
How to Receive Nsnotifications from Uiwebview Embedded Youtube Video Playback
Add Views in Uistackview Programmatically
How to Get a Plist as a Dictionary in Swift
How to Detect Collision in Swift, Sprite Kit
Undocumented Nsurlerrordomain Error Codes (-1001, -1003 and -1004) Using Storekit