Xcode 8 Beta 4 CGColor.components unavailable - core-graphics

Whilst the code below worked previously, it has stopped working in Xcode 8 Beta 4, presumably because the components return was a very un-Swift-y C-array of floats, and has been removed. The error is bald - "'components' is unavailable" - and I can't find what has replaced it, if anything. Does anyone know how to produce the same functionality?
public var cgColour: CGColor {
get {
return CGColor(red: self.colourRed, green: self.colourGreen, blue: self.colourBlue, alpha: self.colourAlpha)
}
set {
let comps = newValue.components // No longer available
self.colourRed = (comps?[0])!
self.colourGreen = (comps?[1])!
self.colourBlue = (comps?[2])!
self.colourAlpha = (comps?[3])!
}
}
Update
#Hamish's answer works, but my original intent was not to use UIColor nor NSColor so that my code works in both iOS & MacOS. What I've ended up doing is this...
#if os(iOS)
import UIKit
#elseif os(OSX)
import Cocoa
#endif
extension CGColor {
var components: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
var r: CGFloat = 0
var g: CGFloat = 0
var b: CGFloat = 0
var a: CGFloat = 0
#if os(iOS)
UIColor(cgColor: self).getRed(&r, green: &g, blue: &b, alpha: &a)
#elseif os(OSX)
NSColor(cgColor: self)?.getRed(&r, green: &g, blue: &b, alpha: &a)
#endif
return (r, g, b, a)
}
}
// Playground code to test...
#if os(iOS)
let rgba = UIColor.brown.cgColor.components //(0.6, 0.4, 0.2, 1.0)
#elseif os(OSX)
let rgba = NSColor.brown.cgColor.components //(0.6, 0.4, 0.2, 1.0)
#endif
... this is such a kludge - has anyone got a better answer?

This looks like a transitional beta issue.
The Swift repo on Github includes an extensive SDK overlay for CoreGraphics, including a new version of CGColor.components whose return type is a Swift array instead of an UnsafePointer. Part of how they make that SDK overlay work is API notes, which map some of the underlying C calls to double-underscore'd Swift methods so that the overlay can wrap them in a more-Swifty interface.
It looks like the beta 4 and beta 5 compilers picked up the API notes change, but not the overlay that includes the new version of components. Presumably a future beta (or the final Swift 3.0 / Xcode 8.0 release) will include everything that's now on github.

#Hamish's answer works, but my original intent was not to use UIColor or NSColor so that my code works in both iOS & MacOS. #LeoDabus suggested using SKColor, but that's just a type alias to either NSColor or UIColor, and doesn't have a direct init from CGColor anyway, however, Leo's suggestion prompted me to refine my kludge using CIColor instead:
import CoreImage
extension CGColor {
var components: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
let ciColor = CIColor(cgColor: self)
return (ciColor.red, ciColor.green, ciColor.blue, ciColor.alpha)
}
}

I'm also a little perplexed as to why they have removed the components property from CGColor, as there doesn't seem to be any kind of obvious replacement method/property. It looks like they're trying to get people to use the higher level UIColor or NSColor classes instead. (As #rickster has discovered, this looks more like a simple transitional issue).
One solution, as you're working with RGB colors, would be to simply wrap your CGColor in a UIColor/NSColor, and then use the getRed(_:green:blue:alpha:) method to get out the components instead.
public var cgColour : CGColor {
get {
return CGColor(red: colourRed, green: colourGreen, blue: colourBlue, alpha: colourAlpha)
}
set {
NSColor(cgColor: newValue)?.getRed(&colourRed, green: &colourGreen, blue: &colourBlue, alpha: &colourAlpha)
}
}
Perhaps not the most ideal solution – would certainly be interested to know if anyone else has a better one, or knows more about this change. Depending on the usage of this property, you may also want to consider simply making it of type UIColor/NSColor to prevent the needless wrapping that this solution requires.

I may be mistaking something, but you can find this in the imported header of CGColor.
/* Return the color components (including alpha) associated with `color'. */
#available(OSX 10.3, *)
public var __unsafeComponents: UnsafePointer<CGFloat>? { get }
Isn't this what you are looking for?
I can write something like this:
public var cgColour: CGColor {
get {
return CGColor(red: self.colourRed, green: self.colourGreen, blue: self.colourBlue, alpha: self.colourAlpha)
}
set {
if let comps = newValue.__unsafeComponents, newValue.numberOfComponents == 4 {
self.colourRed = comps[0]
self.colourGreen = comps[1]
self.colourBlue = comps[2]
self.colourAlpha = comps[3]
}
}
}
It works as I expect, but I'm not sure it's as you expect, or Apple would treat this as using a private API. (Apple's latest documentation of CGColor does not contain double-underscore leaded symbols.)

extension UIColor {
var all4Components:(red:CGFloat, green:CGFloat, blue: CGFloat, alpha:CGFloat) {
let components = self.cgColor.components!
let red = components[0]
let green = components[1]
let blue = components[2]
let alpha = components[3]
return (red:red, green:green, blue: blue, alpha:alpha)
}
}

Related

OSMDroid get the radius of the map

I'm using OSMDroid (Open Street Map for Android), and I'm trying to get the radius of the visible map, to send it to my API and get a result scaled correctly.
Here is what I'm doing on iOS using MapKit to achieve this:
extension MKMapView {
func topLeftCoordinate() -> CLLocationCoordinate2D {
return self.convert(CGPoint(x: 0, y: 0), toCoordinateFrom: self)
}
func currentRadius() -> Double {
let topLeftCoordinate = self.topLeftCoordinate()
return sqrt(pow(centerCoordinate.latitude - topLeftCoordinate.latitude, 2) + pow(centerCoordinate.longitude - topLeftCoordinate.longitude, 2))
}
}
OSMDroid is having a zoomLevel but I'm unable to find a way to convert it to what I need, keeping the correct scaling for API.
Thanks in advance for any help or lead.
I finally found a working solution. It's some kind of magic, but it seems to work correctly (constants were adapted a lot of times before getting the result)
fun MapView.currentRadius(): Double {
// This is magic
return 400 / 2.toDouble().pow(zoomLevelDouble)
}

Programming a UIButton is not working in Swift 4 Xcode 9 Beta 6, Cannot add target

In the past I had no problem creating a UIButton programmatically, but ever since I've been using Xcode 9 and Swift 4, I cannot find a way to make this error go away.
//Adding target to UIButton
func PositionStartButton(xOffset: Float){
StartButton.frame = CGRect(x: Int(0 - 40 + xOffset), y: 0, width: 80, height: 80)
StartButton.setImage(#imageLiteral(resourceName: "Logo_Final_WHITE_Face"), for: .normal)
StartButton.addTarget(self, action: "pressButton:", for: .touchUpInside)
ScrollView.addSubview(StartButton)
}
//The target function
func pressButton(_ sender: UIButton){
print("\(sender)")
}
Error Message: 'NSInvalidArgumentException', reason: '-[Playing.MainMenuViewController pressButton:]: unrecognized selector sent to instance 0x10440a6b0'
Two points.
First, since Swift 2.2 (bundled with Xcode 7.3, released more than a year ago), recommended selector notation is #selector(...). With using the notation, you may get more useful diagnostic messages, than using other notation.
(You should not ignore any warnings displayed with recommended settings.)
Seconde, in Swift 4, you need to explicitly annotate methods invoked through selector with #objc. (In very limited cases, Swift implicitly applies the notation, but not many.)
So, your code shown should be:
//Adding target to UIButton
func PositionStartButton(xOffset: Float){
StartButton.frame = CGRect(x: Int(0 - 40 + xOffset), y: 0, width: 80, height: 80)
StartButton.setImage(#imageLiteral(resourceName: "Logo_Final_WHITE_Face"), for: .normal)
StartButton.addTarget(self, action: #selector(self.pressButton(_:)), for: .touchUpInside) //<- use `#selector(...)`
ScrollView.addSubview(StartButton)
}
//The target function
#objc func pressButton(_ sender: UIButton){ //<- needs `#objc`
print("\(sender)")
}
This is not critical, but you should better follow a simple coding rule of Swift -- only type names are capitalized.
Better rename your PositionStartButton, StartButton and ScrollView, if you think you may have another chance to show your code publicly.
// Add Target
buttonName.addTarget(self, action: #selector(ViewController.handleButton(_:)), for: .touchUpInside)
// Handle Action
#objc func handleButton(_ sender: AnyObject) {
}

Objective-C semantic equivalent written in Swift [duplicate]

The Apple documentation shows an unsettling blank space under the 'Creating a Dictionary' section of the UIKit reference here.
Has anyone found a replacement for the NSDictionaryOfVariableBindings macro, or are we expected to just write our own?
EDIT - According to this perhaps the right approach is to write a global function to handle this? Looks like complex macros are out entirely.
According to Apple source code:
NSDictionaryOfVariableBindings(v1, v2, v3) is equivalent to [NSDictionary dictionaryWithObjectsAndKeys:v1, #"v1", v2, #"v2", v3, #"v3", nil];
So in Swift you can do the same using:
let bindings = ["v1": v1, "v2": v2, "v3": v3]
NSDictionaryOfVariableBindings is, as you say, a macro. There are no macros in Swift. So much for that.
Nonetheless, you can easily write a Swift function to assign string names to your views in a dictionary, and then pass that dictionary into constraintsWithVisualFormat. The difference is that, unlike Objective-C, Swift can't see your names for those views; you will have to let it make up some new names.
[To be clear, it isn't that your Objective-C code could see your variable names; it's that, at macro evaluation time, the preprocessor was operating on your source code as text and rewriting it — and so it could just use the text of your variable names both inside quotes (to make strings) and outside (to make values) to form a dictionary. But with Swift, there is no preprocessor.]
So, here's what I do:
func dictionaryOfNames(arr:UIView...) -> Dictionary<String,UIView> {
var d = Dictionary<String,UIView>()
for (ix,v) in arr.enumerate(){
d["v\(ix+1)"] = v
}
return d
}
And you call it and use it like this:
let d = dictionaryOfNames(myView, myOtherView, myFantasicView)
myView.addConstraints(
NSLayoutConstraint.constraintsWithVisualFormat(
"H:|[v2]|", options: nil, metrics: nil, views: d)
)
The catch is that it is up to you to realize that the name for myOtherView in your visual format string will be v2 (because it was second in the list passed in to dictionaryOfNames()). But I can live with that just to avoid the tedium of typing out the dictionary by hand every time.
Of course, you could equally have written more or less this same function in Objective-C. It's just that you didn't bother because the macro already existed!
That functionality is based on macro expansion which is currently not supported in Swift.
I do not think there is any way to do something similar in Swift at the moment. I believe you cannot write your own replacement.
I'm afraid you'll have to manually unroll the dictionary definition, even if it means repeating each name twice.
So I hacked something together which seems to work:
func dictionaryOfVariableBindings(container: Any, views:UIView...) -> Dictionary<String, UIView> {
var d = Dictionary<String, UIView>()
let mirror = Mirror(reflecting: container)
let _ = mirror.children.compactMap {
guard let name = $0.label, let view = $0.value as? UIView else { return }
guard views.contains(view) else { return }
d[name] = view
}
return d
}
Usage:
let views = dictionaryOfVariableBindings(container: self, views: imageView)
ObjC runtime to the rescue!
i created an alternate solution, but it only works if each of the views are instance variables of the same object.
func DictionaryOfInstanceVariables(container:AnyObject, objects: String ...) -> [String:AnyObject] {
var views = [String:AnyObject]()
for objectName in objects {
guard let object = object_getIvar(container, class_getInstanceVariable(container.dynamicType, objectName)) else {
assertionFailure("\(objectName) is not an ivar of: \(container)");
continue
}
views[objectName] = object
}
return views
}
can be used like this:
class ViewController: UIViewController {
var childA: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = UIColor.redColor()
return view
}()
var childB: UIButton = {
let view = UIButton()
view.setTitle("asdf", forState: .Normal)
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = UIColor.blueColor()
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(childA)
self.view.addSubview(childB)
let views = DictionaryOfInstanceVariables(self, objects: "childA", "childB")
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[childA]|", options: [], metrics: nil, views: views))
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[childB]|", options: [], metrics: nil, views: views))
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[childA][childB(==childA)]|", options: [], metrics: nil, views: views))
}
}
unfortunately you still have to type the variable name in as a string, but it will at least assert if there is a typo. this definitely won't work in all situations, but helpful nonetheless
Based on https://stackoverflow.com/a/55086673/1058199 by cherpak-evgeny, this UIViewController extension assumes that the container is self, the current viewController instance.
extension UIViewController {
// Alex Zavatone 06/04/2019
// Using reflection, get the string name of the UIView properties passed in
// to create a dictionary of ["viewPropertyName": viewPropertyObject…] like
// Objective-C's NSDictionaryForVariableBindings.
func dictionaryOfBindings(_ arrayOfViews:[UIView?]) -> Dictionary<String, UIView> {
var bindings = Dictionary<String, UIView>()
let viewMirror = Mirror(reflecting: self)
let _ = viewMirror.children.compactMap {
guard let name = $0.label, let view = $0.value as? UIView else { return }
guard arrayOfViews.contains(view) else { return }
bindings[name] = view
}
return bindings
}
}
Use it like so from within your viewController:
let viewArray = [mySwitch, myField, mySpinner, aStepper, someView]
let constraintsDictionary = dictionaryOfBindings(viewArray)
Tested in Xcode 10.2.1 and Swift 4.2.
Many thanks to Cherpak Evgeny for writing it in the first place.
Once you've stored all your views as properties, you could also use reflection like so:
extension ViewController {
func views() -> Dictionary<String, AnyObject> {
var views = dictionaryOfProperties()
views.forEach {
if !($1 is UIView) {
views[$0] = nil
}
}
return views
}
}
extension NSObject {
func dictionaryOfProperties() -> Dictionary<String, AnyObject> {
var result = Dictionary<String, AnyObject>()
let mirror = Mirror(reflecting: self)
for case let(label?, value) in mirror.children {
result[label] = value as? AnyObject
}
return result
}
}

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.

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()
}