PRTweenOperation timingFunction member not found in Swift - objective-c

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

Related

Swift parameters are not visible inside of Objective C Function?

Some background: I'm building an app in react native that uses an Objective C library written about 6 or 7 years ago, maybe older. I'm writing swift code that has been set up to send callbacks to the react native application in JS. I have this function that I'm trying to use:
token = service.getUserToken(server,
port: P2PFunctions.tls_port,
appId: P2PFunctions.appID,
appSecret: P2PFunctions.appSecret,
phone: P2PFunctions.phone,
token: nil, errcode: errCode, errmsg: nil);
callback(["\(token!)"]);
And this is its definition:
- (NSInteger)getUserToken:(NSString*)ip_In port:(NSInteger)port_In appId:
(NSString*)appId_In appSecret:(NSString*)appSecret_In phone:
(NSString*)phoneNum_In token:(NSString**)accessTok_Out errcode:
(NSString**)strErrCode_Out errmsg:(NSString**)errMsg_Out;
These are the types I'm using (EDIT: I changed them from private to public, and they still are not being recognized):
The problem is, I'm getting nil back from the function. I believe I'm getting an HTTP response that is empty, and I notice that inside the debugger when I step to the Objective C function, I see nil for all my parameters inside of the Objective C function. I think... it is that I'm not passing the correct type. Or my Swift parameters are not visible in Objective C's memory space. If it is expecting an (NSString *), should I be passing a String?
How do I pass the correct types from Swift to Objective C? What would I change in my function call? Are my parameter types okay? I cannot edit the original Objective C library. They share a common memory space for all variables in the entire program, right?
Thank you so much!
I just ran this successfully:
// the objc part
#interface Test : NSObject
- (NSInteger)getUserToken:(NSString*)ip_In
port:(NSInteger)port_In
appId:(NSString*)appId_In
appSecret:(NSString*)appSecret_In
phone:(NSString*)phoneNum_In
token:(NSString* _Nonnull * _Nonnull)accessTok_Out
errcode:(NSString* _Nonnull * _Nonnull)strErrCode_Out
errmsg:(NSString* _Nonnull * _Nonnull)errMsg_Out;
#end
#implementation Test
- (NSInteger)getUserToken:(NSString*)ip_In
port:(NSInteger)port_In
appId:(NSString*)appId_In
appSecret:(NSString*)appSecret_In
phone:(NSString*)phoneNum_In
token:(NSString**)accessTok_Out
errcode:(NSString**)strErrCode_Out
errmsg:(NSString**)errMsg_Out {
*accessTok_Out = #"Token";
*strErrCode_Out = #"OK";
*errMsg_Out = #"msg";
return 42;
}
#end
// and the swift part
let t = Test()
var token: NSString = "t"
var errcode: NSString = "c"
var errmsg: NSString = "m"
let result = t.getUserToken("ip", port: 1,
appId: "2", appSecret: "3", phone: "4",
token: &token, errcode: &errcode, errmsg: &errmsg)
print(result)
and it works as expected.
Maybe this gives you a hint as to what's different in your situation.
So, after spending a week or so on this problem, I realize that it was not that the parameters are not actually being passed, but that the debugger is just not displaying the values of those parameters, at least on the main thread. Because I was getting the error code, I thought that something had to be wrong with the way I called the function - but actually, the function call is fine, the variables just didn't appear in the debugger for some reason:
Variables above appear to be nil - but in fact, they do have values.

Cannot invoke 'global' with an argument list of type '(Int, Int)'

I am on the process of migrating old swift code to Swift 3.0, and at times via Swift 2.3.
On the way I made some wrong actions, leading to a mix up of different versions here and there.
That said I must now fall back on my feet and make things work.
Here some code I have:
let qualityOfServiceClass = QOS_CLASS_BACKGROUND
let backgroundQueue = DispatchQueue.global(Int(qualityOfServiceClass.rawValue), 0)
backgroundQueue.asynchronously(execute: {
self.getAppData()
self.waitingForAppData = false
self.busyWithAppDataAccess = false
})
And here is an error message I get, relative to the code above:
Cannot invoke 'global' with an argument list of type '(Int, Int)'
Does anyone know what the problem is here?
I cannot find a matching signature for your use of the global method. I'm assuming that the second Int is suppose to represent the relative priority.
Since global(priority:) has been deprecated. Here is how you could update your code for Swift 3:
let backgroundQueue = DispatchQueue.global(qos: .background)
backgroundQueue.async {
self.getAppData()
self.waitingForAppData = false
self.busyWithAppDataAccess = false
}
You could also do this to keep relative priority in the picture. However, it doesn't seem to be relevant anymore when using Swift 3.
let qos = DispatchQoS(qosClass: .background, relativePriority: 0)
let backgroundQueue = DispatchQueue.global(qos: qos.qosClass)
backgroundQueue.async {
self.getAppData()
self.waitingForAppData = false
self.busyWithAppDataAccess = false
}

Can't use Sphero collision detection with Swift?

I'm new to Swift and Sphero development but I've been asked to do a game based on collisions with the Sphero.
I've managed to implement the driving part without problems so far, but I'm having problems with collisions.
I've been looking for code examples and similar issues all over the Internet but everything I've found is based in other languages like JAVA or ObjectiveC.
The code provided by Sphero's official page is the following:
**Enable collision detection**
robot.enableCollisions(true)
robot.sendCommand(RKConfigureCollisionDetectionCommand(forMethod: .Method3, xThreshold: 50, xSpeedThreshold: 30, yThreshold: 200, ySpeedThreshold: 0, postTimeDeadZone: 0.2))
**Handle Async Messages on collision**
func handleAsyncMessage(message: RKAsyncMessage!, forRobot robot: RKRobotBase!) {
if let collisionMessage = message as? RKCollisionDetectedAsyncData {
// handleCollisionDetected
}
}
I've tried this in many ways, but when executed it won't send any command or even access the handleAsyncMessage method, so I'm starting to think this code is not implemented for Swift.
These doubts were intensified when I found that the collision streaming method was implemented somewhere in the official page for ObjectiveC, but for Swift I could only find //Coming Soon!.
Collisions
[_robot sendCommand:[[RKConfigureCollisionDetectionCommand alloc]
initForMethod:RKCollisionDetectionMethod3
xThreshold:50 xSpeedThreshold:30 yThreshold:200 ySpeedThreshold:0 postTimeDeadZone:.2]];
...
- (void)handleAsyncMessage:(RKAsyncMessage *)message forRobot:(id<RKRobotBase>)robot {
if( [message isKindOfClass:[RKCollisionDetectedAsyncData class]]) {
RKCollisionDetectedAsyncData *collisionAsyncData = (RKCollisionDetectedAsyncData *) message;
float impactAccelX = [collisionAsyncData impactAcceleration].x;
float impactAccelY = [collisionAsyncData impactAcceleration].y;
float impactAccelZ = [collisionAsyncData impactAcceleration].z;
float impactAxisX = [collisionAsyncData impactAxis].x;
float impactAxisY = [collisionAsyncData impactAxis].y;
float impactPowerX = [collisionAsyncData impactPower].x;
float impactPowerY = [collisionAsyncData impactPower].y;
float impactSpeed = [collisionAsyncData impactSpeed];
}
}
Should I change the language to ObjectiveC or do you guys know any way to implement this using Swift?
Thank you in advance.
This SDK is written in Objective-C; Swift works through Objective-C interoperability built into Swift. Everything should work regardless of the language you choose. It looks like you might be missing the response observer. On the robot you call robot.addResponseObserver(self) making sure you implement the RKResponseObserver protocol.

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)

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.