How do you compare NSFontSymbolicTraits and NSFontBoldTrait in Swift? - objective-c

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)

Related

Cannot find * in scope

I'm migrating objective C to swift. I'm getting the error Cannot find 'NSUtils' in scope in the line-
_idInstance = NSUtils.sha256(_idInstance)
I have the NSUtils class in objective C. The function is also mentioned there and it's working well with other .m files:
+ (NSString *)sha256:(NSString *)clear {
....
}
The autofill suggestions also don't show for this. Please help.
In Swift, you should really use CryptoKit instead:
import CryptoKit
let digest = SHA256.hash(data: myData)
let digestString = String(bytes: digest.map { $0 }, encoding: .ascii)!

Unable to set value via protocol

In my Objective C code I had this:
if ([view conformsToProtocol:#protocol(UITextInputTraits)]) {
id<UITextInputTraits> field = view;
field.enablesReturnKeyAutomatically = YES;
}
Now I'm trying to convert that to swift, so I did this:
if var field = view as? UITextInputTraits {
field.enabledReturnKeyAutomatically = true
}
I'm getting a compiler error saying that 'field' is immutable. What's the right way to accomplish this?
The problem is caused by Swift's peculiar way of dealing with optional protocol requirements. Optional protocol properties have no setter. (I regard this as a bug in the language.) You'll have to work around it.
You can say (horrible):
switch view {
case let field as UITextField:
field.enablesReturnKeyAutomatically = true
case let field as UITextView:
field.enablesReturnKeyAutomatically = true
default: break
}
Another way (equally horrible):
let setter = #selector(setter:UITextInputTraits.enablesReturnKeyAutomatically)
if view.responds(to:setter) {
view.perform(setter, with: 1 as NSNumber)
}

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.)

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).

Cocoa check if function exists

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.