Cocoa check if function exists - objective-c

I'd like to use a function that's only available on OS X 10.9, but WITHOUT compiling with the 10.9 SDK. Is that possible?
I've tried weak linking, but the compiler just gives out an error that the function is not defined.

You say you don't want to compile against 10.9, but give no reason. Just in case you can:
If you set your target to 10.9 and your deployment to something lower then Xcode will weak link the 10.9 frameworks. You can then test for a C function being available by comparing its name to NULL. This fragment is taken from this document:
extern int MyWeakLinkedFunction() __attribute__((weak_import));
int main()
{
int result = 0;
if (MyWeakLinkedFunction != NULL)
{
result = MyWeakLinkedFunction();
}
return result;
}
(BTW: no sandbox issues this way.)

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.

If you are dealing with Objective-C methods, maybe you could do it with selectors..
So first check if the selector is available with:
[object respondsToSelector:#selector(osxMavericksFun)]
And if this test is correct try firing the Method via selectors
[object performSelector:#selector(osxMavericksFun)];
If you want to call c functions there is no way to do this.

You should do it like this
if (AXIsProcessTrustedWithOptions != NULL){
NSDictionary *options = #{(__bridge id)kAXTrustedCheckOptionPrompt: #YES};
accessibilityEnabled = AXIsProcessTrustedWithOptions((__bridge CFDictionaryRef)options);
}else{
accessibilityEnabled = AXIsProcessTrusted();
}
This method is described in apple's documentation Listing 3-2. It is much simpler than the method described by Richard J. Ross III which you accepted as correct.

Related

How do you compare NSFontSymbolicTraits and NSFontBoldTrait in Swift?

I'm trying to bitwise compare NSFontSymbolicTraits and NSFontBoldTrait in Swift.
In Objective-C it'd be done like this:
BOOL isBold = (fontDescriptorSymbolicTraits & UIFontDescriptorTraitBold);
So I'm thinking it should be this in Swift:
let isBold:Bool = font.fontDescriptor.symbolicTraits & NSFontBoldTrait
...However that results in the following error:
Cannot invoke '&' with an argument list of type '(NSFontSymbolicTraits, Int)'
Anyone know what I'm missing? Any help would be greatly appreciated.
Notes:
I've Googled like a madman and spend hours trying to find a solution and read through the documentation for NSFontDescriptor and the other NSFont-related classes.
I don't know Obj-C very well so I don't know if it's because the NSFont*Trait constants are implemented differently in Swift? Not even sure if that's the case.
In Swift, NSFontSymbolicTraits is a type alias for UInt32. So to check for the existence of a particular trait, you need to compare the result of your bitwise & to zero. Unfortunately, the individual constraints have been imported as type Int, so you also need to convert them to the right type:
let isBold = 0 != (font.fontDescriptor.symbolicTraits & NSFontSymbolicTraits(NSFontBoldTrait))
If you wanted to do this in iOS (instead of OS X), UIFont has a different implementation. UIFontDescriptorSymbolicTraits is a RawOptionSetType, so you compare the result of your & with nil:
let isBold = nil != (font.fontDescriptor().symbolicTraits & UIFontDescriptorSymbolicTraits.TraitBold)
Update based on Nates answer, since his iOS version doesn't work for me. Which most likely is due to the changes in swift since 2014.
iOS, Swift 4(.2):
extension UIFontDescriptor {
var isBold: Bool {
if 0 == (symbolicTraits.rawValue & UIFontDescriptor.SymbolicTraits.traitBold.rawValue) {
return false
} else {
return true
}
}
}
In Swift 5.4 on iOS.
let isBold = font.fontDescriptor.symbolicTraits.contains(.traitBold)

PRTweenOperation timingFunction member not found in Swift

I'm trying to use the PRTween library in a Swift iPhone app.
Original example code from GitHub:
PRTweenPeriod *period = [PRTweenPeriod periodWithStartValue:100 endValue:200 duration:3];
PRTweenOperation *operation = [[PRTweenOperation new] autorelease];
operation.period = period;
operation.target = self;
operation.timingFunction = &PRTweenTimingFunctionLinear;
My Swift port:
var period = PRTweenPeriod.periodWithStartValue(100, endValue: 200, duration: 3) as PRTweenPeriod
var operation = PRTweenOperation()
operation.period = period
operation.target = self
operation.timingFunction = PRTweenTimingFunctionLinear
Xcode is giving me this error:
'PRTweenOperation' does not have a member named 'timingFunction'
I'm not sure how to fix this. I can clearly see the member definition in PRTween.h. I'm thinking it might be related to the fact that this is where the definition of PRTweenTimingFunction takes me.
typedef CGFloat(*PRTweenTimingFunction)(CGFloat, CGFloat, CGFloat, CGFloat);
Has anyone else seen an error like this? Any suggestions for fixes?
P.S. I'm not really sure what to call that typedef. Is it a function pointer?
EDIT
As a workaround, I used this code that does not ask for a timing function:
let period = PRTweenPeriod.periodWithStartValue(100, endValue: 200, duration: 2) as PRTweenPeriod
PRTween.sharedInstance().addTweenPeriod(period,
updateBlock: { (p: PRTweenPeriod!) in
NSLog("\(Int(p.tweenedValue))"
},
completionBlock: { NSLog("Completed tween") })
Yes, that's a function pointer. This is a current limitation of C interoperability:
Note that C function pointers are not imported in Swift.
You might consider filing a bug if you'd like this to work. (Note that block-based APIs are fine and work with Swift closures.)

respondsToSelector: equivalent for CoreFoundation?

I have a CFArrayRef which mostly has CFDictionaryRef, but sometimes it'll contain other things. I'd like to access a value from the dictionary in the array if I can, and not crash if I can't. Here's the code:
bool result = false;
CFArrayRef devices = CFArrayCreateCopy(kCFAllocatorDefault, SDMMobileDevice->deviceList);
if (devices) {
for (uint32_t i = 0; i < CFArrayGetCount(devices); i++) {
CFDictionaryRef device = CFArrayGetValueAtIndex(devices, i);
if (device) { // *** I need to verify this is actually a dictionary or actually responds to the getObjectForKey selector! ***
CFNumberRef idNumber = CFDictionaryGetValue(device, CFSTR("DeviceID"));
if (idNumber) {
uint32_t fetched_id = 0;
CFNumberGetValue(idNumber, 0x3, &fetched_id);
if (fetched_id == device_id) {
result = true;
break;
}
}
}
}
CFRelease(devices);
}
return result;
Any suggestions for how I can ensure that I only treat device like a CFDictionary if it's right to do so?
(I'm dealing with some open source code that isn't particularly well documented, and it doesn't seem to be particularly reliable either. I'm not sure if it's a bug that the array contains non-dictionary objects or a bug that it doesn't detect when it contains non-dictionary objects, but it seems to me that adding a check here is less likely to break other code then forcing it to only contain dictionaries elsewhere. I don't often work with CoreFoundation, so I'm not sure if I'm using the proper terms.)
In this case, since it looks like you are traversing the I/O Registry, you can use CFGetTypeId():
CFTypeRef device = CFArrayGetValueAtIndex(devices, i); // <-- use CFTypeRef
if(CFGetTypeID(device) == CFDictionaryGetTypeID()) { // <-- ensure it's a dictionary
...
}
If you really need to send messages to NSObject's interface from your C code, you can (see #include <objc/objc.h> and friends, or call to a C helper function in a .m file), but these strategies are not as straight forward as CFGetTypeID(), and much more error-prone.

CFStringGetCStringPtr returns NULL on iOS7

I have the following code in my Application:
static void foo(CFStringRef str)
{
CFStringEncoding encoding = CFStringGetSystemEncoding();
const char * cString = CFStringGetCStringPtr(str, encoding);
//.....
}
It's been around since iOS 5, and always worked.
Since iOS 7 release, CFStringGetCStringPtr returns NULL.
Adding the following code, have solved it:
if (cString==NULL)
{
cString = [
((NSString *)str) cStringUsingEncoding:[NSString defaultCStringEncoding]
];
}
Still, I would like to know if anyone knows what causes the problem?
CFStringGetCStringPtr() isn't guaranteed to return non-NULL. From the docs (emphasis added):
Whether or not this function returns a valid pointer or NULL depends on many factors, all of which depend on how the string was created and its properties. In addition, the function result might change between different releases and on different platforms. So do not count on receiving a non-NULL result from this function under any circumstances.
Always have a fallback to CFStringGetCString(), but even better, use Objective-C and NSString's helper methods (e.g. UTF8String).

iOS: How to convert UIViewAnimationCurve to UIViewAnimationOptions?

The UIKeyboardAnimationCurveUserInfoKey has a UIViewAnimationCurve value. How do I convert it to the corresponding UIViewAnimationOptions value for use with the options argument of +[UIView animateWithDuration:delay:options:animations:completion:]?
// UIView.h
typedef enum {
UIViewAnimationCurveEaseInOut, // slow at beginning and end
UIViewAnimationCurveEaseIn, // slow at beginning
UIViewAnimationCurveEaseOut, // slow at end
UIViewAnimationCurveLinear
} UIViewAnimationCurve;
// ...
enum {
// ...
UIViewAnimationOptionCurveEaseInOut = 0 << 16, // default
UIViewAnimationOptionCurveEaseIn = 1 << 16,
UIViewAnimationOptionCurveEaseOut = 2 << 16,
UIViewAnimationOptionCurveLinear = 3 << 16,
// ...
};
typedef NSUInteger UIViewAnimationOptions;
Obviously, I could create a simple category method with a switch statement, like so:
// UIView+AnimationOptionsWithCurve.h
#interface UIView (AnimationOptionsWithCurve)
#end
// UIView+AnimationOptionsWithCurve.m
#implementation UIView (AnimationOptionsWithCurve)
+ (UIViewAnimationOptions)animationOptionsWithCurve:(UIViewAnimationCurve)curve {
switch (curve) {
case UIViewAnimationCurveEaseInOut:
return UIViewAnimationOptionCurveEaseInOut;
case UIViewAnimationCurveEaseIn:
return UIViewAnimationOptionCurveEaseIn;
case UIViewAnimationCurveEaseOut:
return UIViewAnimationOptionCurveEaseOut;
case UIViewAnimationCurveLinear:
return UIViewAnimationOptionCurveLinear;
}
}
#end
But, is there an even easier/better way?
The category method you suggest is the “right” way to do it—you don’t necessarily have a guarantee of those constants keeping their value. From looking at how they’re defined, though, it seems you could just do
animationOption = animationCurve << 16;
...possibly with a cast to NSUInteger and then to UIViewAnimationOptions, if the compiler feels like complaining about that.
Arguably you can take your first solution and make it an inline function to save yourself the stack push. It's such a tight conditional (constant-bound, etc) that it should compile into a pretty tiny piece of assembly.
Edit:
Per #matt, here you go (Objective-C):
static inline UIViewAnimationOptions animationOptionsWithCurve(UIViewAnimationCurve curve)
{
switch (curve) {
case UIViewAnimationCurveEaseInOut:
return UIViewAnimationOptionCurveEaseInOut;
case UIViewAnimationCurveEaseIn:
return UIViewAnimationOptionCurveEaseIn;
case UIViewAnimationCurveEaseOut:
return UIViewAnimationOptionCurveEaseOut;
case UIViewAnimationCurveLinear:
return UIViewAnimationOptionCurveLinear;
}
}
Swift 3:
extension UIViewAnimationOptions {
init(curve: UIViewAnimationCurve) {
switch curve {
case .easeIn:
self = .curveEaseIn
case .easeOut:
self = .curveEaseOut
case .easeInOut:
self = .curveEaseInOut
case .linear:
self = .curveLinear
}
}
}
In Swift you can do
extension UIViewAnimationCurve {
func toOptions() -> UIViewAnimationOptions {
return UIViewAnimationOptions(rawValue: UInt(rawValue << 16))
}
}
An issue with the switch based solution is that it assumes no combination of options will be ever passed in. Practice shows though, that there may be situations where the assumption doesn't hold. One instance I found is (at least on iOS 7) when you obtain the keyboard animations to animate your content along with the appearance/disappearance of the keyboard.
If you listen to the keyboardWillShow: or keyboardWillHide: notifications, and then get the curve the keyboard announces it will use, e.g:
UIViewAnimationCurve curve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue];
you're likely to obtain the value 7. If you pass that into the switch function/method, you won't get a correct translation of that value, resulting in incorrect animation behaviour.
Noah Witherspoon's answer will return the correct value. Combining the two solutions, you might write something like:
static inline UIViewAnimationOptions animationOptionsWithCurve(UIViewAnimationCurve curve)
{
UIViewAnimationOptions opt = (UIViewAnimationOptions)curve;
return opt << 16;
}
The caveat here, as noted by Noah also, is that if Apple ever changes the enumerations where the two types no longer correspond, then this function will break. The reason to use it anyway, is that the switch based option doesn't work in all situations you may encounter today, while this does.
iOS 10+
Swift 5
A Swift alternative to converting UIView.AnimationCurve to UIView.AnimationOptions, which may not even be possible, is to use UIViewPropertyAnimator (iOS 10+), which accepts UIView.AnimationCurve and is a more modern animator than UIView.animate.
Most likely you'll be working with UIResponder.keyboardAnimationCurveUserInfoKey, which returns an NSNumber. The documentation for this key is (Apple's own notation, not mine):
public class let keyboardAnimationCurveUserInfoKey: String // NSNumber of NSUInteger (UIViewAnimationCurve)
Using this approach, we can eliminate any guesswork:
if let kbTiming = notification.userInfo?[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber, // doc says to unwrap as NSNumber
let timing = UIView.AnimationCurve.RawValue(exactly: kbTiming), // takes an NSNumber
let curve = UIView.AnimationCurve(rawValue: timing) { // takes a raw value
let animator = UIViewPropertyAnimator(duration: duration, curve: curve) {
// add animations
}
animator.startAnimation()
}