Check If a Func Exists in Swift

Check if a function is available in Swift?

A proper check for availability has been added in Swift 2. This is recommended over other options mentioned here.

var shouldApplyMotionEffects = true
if #available(iOS 8.0, *) {
shouldApplyMotionEffects = !UIAccessibilityIsReduceMotionEnabled()
}

Check existence of global function in Swift

Swift currently does not support looking up global functions.

For C functions (most global functions from Apple's frameworks are C functions) there are at least two ways:

  • using a weakly linked symbol
  • the dynamic linker API: dlopen

Both check dynamically (at runtime) if a symbol can be found.

Here's an example that checks if UIGraphicsBeginImageContextWithOptions (introduced with iOS 4) is available:

void UIGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque, CGFloat scale) __attribute__((weak));

static inline BOOL hasUIGraphicsBeginImageContextWithOptions() {
return UIGraphicsBeginImageContextWithOptions != NULL;
}

Here's the same check, using dlsym:

#import <dlfcn.h>

static inline BOOL hasUIGraphicsBeginImageContextWithOptions() {
return dlsym(RTLD_SELF, "UIGraphicsBeginImageContextWithOptions") != NULL;
}

The advantage of using dlsym is that you don't need a declaration and that it's easily portable to Swift.

Cocoa check if function exists

Assuming you are talking about a C function, you can do this with the dlopen function:

#include <dlfcn.h>

int main() {
void *lib = dlopen("/System/Library/Frameworks/ApplicationServices.framework/ApplicationServices", RTLD_LAZY);
void *function = dlsym(lib, "CGColorGetConstantColor");

// cast the function to the right format
CGColorRef (*dynamic_getConstantColor)(CFStringRef colorName) = function;

NSLog(@"%@", dynamic_getConstantColor(CFSTR("kCGColorBlack")));

dlclose(lib);
}

Output:


2013-06-20 12:43:13.510 TestProj[1699:303] [ (kCGColorSpaceICCBased; kCGColorSpaceModelMonochrome; Generic Gray Profile)] ( 0 1 )

You will need to figure out the dylib in which the function you want resides, first, though.

This will break the sandbox limitations on iOS, and Mac most likely as well. It is the price you pay for trying to get around the linker.

Check if variable is a block / function / callable in Swift

You can check the String representation of .dynamicType of the callable for existence of substring ->. Not super-elegant, but it works:

func isAClosure<T>(foo: T) -> Bool {
return String(foo.dynamicType).containsString("->")
}

var a : () -> () = { print("Foobar") }
var b : (Double) -> (Bool) = { $0 > 0 }
var c : Int = 1

isAClosure(a) // true
isAClosure(b) // true
isAClosure(c) // false

Of course, as Marcus Rossel points out in the comment above, you still wouldn't know anything about the parameters of the callable (but perhaps that could be next step to find out, given that you know it's a callable).


Addition with regard to OPs questions below: just a technical discussion, and not recommended techniques.

You use the same approach as above to check if the function argument is a closure without arguments (() -> (...)) or one with neither arguments nor return type (() -> ()), and so on. Using this approach, you can define a generic function that call the argument sent to the function only if it is of a certain closure type. For this "in-function-call", you'll have to make use of type conversion to expected closure type, much as you've described in your Q above. It'll probably be difficult to circumvent this "non-generic" approach w.r.t. calling the closures. A few examples follow below.

/* Example functions */
func isAVoidParamClosure<T>(foo: T) -> Bool {
let bar = String(foo.dynamicType).componentsSeparatedByString(" -> ")
return bar.count > 1 && (bar.first?.characters.count ?? 0) == 2
}

func callIfVoidVoidClosure<T>(foo: T) {
let bar = String(foo.dynamicType).componentsSeparatedByString(" -> ")
if bar.count > 1 && !(bar.map{ $0 == "()" }.contains(false)) {
if let foo = foo as? () -> () {
foo()
}
}
}

func isASingleDoubleReturnTypeClosure<T>(foo: T) -> Bool {
let bar = String(foo.dynamicType).componentsSeparatedByString(" -> ")
return bar.count > 1 && bar[1] == "Double"
/* rhs of '&&' lazily evaluated: [1] ok */
}

func printTwoTimesResultOfVoidDoubleClosure<T>(foo: T) {
if isAVoidParamClosure(foo) && isASingleDoubleReturnTypeClosure(foo) {
if let foo = foo as? () -> Double {
let a: Double = 2*foo()
print(a)
}
}
}

Example calls:

/* Example calls */
let a : () -> () = { print("Foobar") }
let b : (Double) -> (Bool) = { $0 > 0 }
let c : () -> Double = { 21.0 }
let d : Int = 1

isAVoidParamClosure(a) // true
isAVoidParamClosure(b) // false
isAVoidParamClosure(c) // true
isAVoidParamClosure(d) // false

callIfVoidVoidClosure(a) // Prints "Foobar"
callIfVoidVoidClosure(b)
callIfVoidVoidClosure(c)
callIfVoidVoidClosure(d)

printTwoTimesResultOfVoidDoubleClosure(a)
printTwoTimesResultOfVoidDoubleClosure(b) // Prints "42.0"
printTwoTimesResultOfVoidDoubleClosure(c)
printTwoTimesResultOfVoidDoubleClosure(d)

Swift - Check if object is of a given type (where the type has been passed as function argument)

I don't know where you are taking myArray. You probably need to create an extension to Array for MyBaseClass. Like this:

extension Array where Element: MyBaseClass {
func myFilter<T: MyBaseClass>(objectType: T.Type) -> [T] {
var filteredArray: [T] = []
for object in self {
if let object = object as? T {
filteredArray.append(object)
}
}

return filteredArray
}
}

Then you can call:

// Example call
let array = [SubclassA(), SubclassA(), SubclassC(), SubclassD()]
array.myFilter(objectType: SubclassD.self) // == [SubclassD()]

EDIT:
Easy solution if you want a return type of myFilter to be just MyBaseClass and you don't want to change the original array would be this:

array.filter { $0 is SubclassD }

Check if the element exists in the array, and then replace between two arrays Swift

If the order of the collection doesnt matter you should use a set to make sure there is no duplicated players in your collection:

var mainPlayers: Set = ["player1", "player2", "player3"]
var secondaryPlayers: Set = ["player4", "player5", "player6"]

let oldPlayer = "player1"
let newPlayer = "player4"
if mainPlayers.contains(oldPlayer),
secondaryPlayers.contains(newPlayer),
let oldMember = mainPlayers.remove(oldPlayer),
let newMember = secondaryPlayers.remove(newPlayer),
mainPlayers.insert(newMember).inserted,
secondaryPlayers.insert(oldMember).inserted {
print("oldMember", oldMember) // player1
print("newMember", newMember) // player4
print(mainPlayers) // ["player3", "player4", "player2"]
print(secondaryPlayers) // ["player1", "player5", "player6"]
}

If the order of the collection matters the array approach should look like this:

var mainPlayers = ["player1", "player2", "player3"]
var secondaryPlayers = ["player4", "player5", "player6"]

if let oldMemberIndex = mainPlayers.firstIndex(of: "player1"),
let newMemberIndex = secondaryPlayers.firstIndex(of: "player4"),
case let oldMember = mainPlayers.remove(at: oldMemberIndex),
case let newMember = secondaryPlayers.remove(at: newMemberIndex) {
mainPlayers.insert(newMember, at: oldMemberIndex)
secondaryPlayers.insert(oldMember, at: newMemberIndex)
print("oldMember", oldMember) // player1
print("newMember", newMember) // player4
print(mainPlayers) // ["player4", "player2", "player3"]
print(secondaryPlayers) // ["player1", "player5", "player6"]
}

Swift extension of Sequence to check if an intersection exists

Well I found the correct syntax, not sure why the other syntax would not work tho :/

If someone could still explain why the other way does not work, it'd be interesting /p>

extension Sequence where Element:Equatable {
func intersects<T:Sequence>(with anotherSequence:T) -> Bool
where T.Element == Self.Element {
return self.contains(where: anotherSequence.contains)
}
}


Related Topics



Leave a reply



Submit