Cast from AnyObject to UIEdgeInsets [duplicate] - swift

As my question title says how can I convert CGPoint into NSValues so I can store then Into array In swift.
In objective-C we can do it like this:
// CGPoint converted to NSValue
CGPoint point = CGPointMake(9, 9);
NSValue *pointObj = [NSValue valueWithCGPoint:point];
But can anybody tell me that how can I do this in swift?
Thanks In Advance.

Try something like that:
let point = CGPointMake(9, 9)
var pointObj = NSValue(CGPoint: point)

Exactly as you'd imagine:
let point = CGPoint(x: 9.0, y: 9.0)
let pointObj = NSValue(CGPoint: point)
let newPoint = pointObj.CGPointValue()

If you aren't planning on using the array in Objective-C, and can keep it as a Swift Array, then you don't need to turn the point into an NSValue, you can just add the point to the array directly:
let point1 = CGPoint(x: 9.0, y: 9.0)
let point2 = CGPoint(x: 10.0, y: 10.0)
let pointArray = [point1, point2] // pointArray is inferred to be of type [CGPoint]
let valuesArray = pointsArray as [NSValue]

swift 3
let pointObj = NSValue(cgPoint: CGPoint(x:9, y:9))
https://developer.apple.com/reference/foundation/nsvalue/1624531-init

swift 4
let point = NSValue.init(cgPoint: mask.position)

Related

CALayer bounds don't change after setting them to a certain value

I am trying to display an image as the content of a CALayer slightly zoomed in by changing its bounds to a bigger size. (This is so that I can pan over it later.)
For some reason however setting the bounds does not change them or trigger an animation to do so.
This is the code I use to change the bounds:
self.imageLayer.bounds = CGRect(x: 0, y: 0, width: 10, height: 10)
I have a function to compute the CGRect, but this dummy one leads to exactly the same result of the size not changing.
I have also determined, that while I can't see the size change, if I check the bounds of the layer right after setting it, it correctly has the value I set it to.
The following code is executed after setting the bounds. I couldn't find anything in it, that changes them back.
self.imageLayer.add(self.generatePanAnimation(), forKey: "pan")
func generatePanAnimation() -> CAAnimation {
var positionA = CGPoint(x: (self.bounds.width / 2), y: self.bounds.height / 2)
var positionB = CGPoint(x: (self.bounds.width / 2), y: self.bounds.height / 2)
positionA = self.generateZoomedPosition()
positionB = self.generateZoomedPosition()
let panAnimation = CABasicAnimation(keyPath: "position")
if self.direction == .AtoB {
panAnimation.fromValue = positionA
panAnimation.toValue = positionB
} else {
panAnimation.fromValue = positionB
panAnimation.toValue = positionA
}
panAnimation.duration = self.panAndZoomDuration
self.panAnimation = panAnimation
return panAnimation
}
func generateZoomedPosition() -> CGPoint {
let maxRight = self.zoomedImageLayerBounds.width / 2
let maxLeft = self.bounds.width - (self.zoomedImageLayerBounds.height / 2)
let maxUp = self.zoomedImageLayerBounds.height / 2
let maxDown = self.bounds.height - (self.zoomedImageLayerBounds.height / 2)
let horizontalFactor = CGFloat(arc4random()) / CGFloat(UINT32_MAX)
let verticalFactor = CGFloat(arc4random()) / CGFloat(UINT32_MAX)
let randomX = maxLeft + horizontalFactor * (maxRight - maxLeft)
let randomY = maxDown + verticalFactor * (maxUp - maxDown)
return CGPoint(x: randomX, y: randomY)
}
I even tried setting the bounds as shown below, but it didn't help.
CATransaction.begin()
CATransaction.setValue(true, forKey: kCATransactionDisableActions)
self.imageLayer.bounds = CGRect(x: 0, y: 0, width: 10, height: 10)
CATransaction.commit()
I really hope someone has an idea. Thanks a lot!
The way to change the apparent drawing size of a layer is not to change its bounds but to change its transform. To make the layer look larger, including its drawing, apply a scale transform.

Type 'Range<CGFloat> does not conform to protocol Sequence' (Swift 3) [duplicate]

This question already has an answer here:
Swift 3: replace c style for-loop with float increment
(1 answer)
Closed 6 years ago.
I am trying to do a for loop here using CGFloat but I am getting an error saying that
Type 'Range does not conform to protocol Sequence'
The code that I am trying to run is as below. The error happens at the "for" loop at the end of the code.
func setupBackgroundSea(){
//putting the background//
let texture = SKTexture(imageNamed: "background")
texture.filteringMode = .nearest
//calculating the number of background images needed//
let needNumber = 2.0 + (self.frame.size.width / texture.size().width)
//creating animation//
let moveAnim = SKAction.moveBy(x: -(texture.size().width), y: 0.0, duration: TimeInterval(texture.size().width/10.0))
let resetAnim = SKAction.moveBy(x: texture.size().width, y: 0.0, duration: 0.0)
let repeatForeverAnim = SKAction.repeatForever(SKAction.sequence([moveAnim,resetAnim]))
//setting the position of the image and the animation//
for var i:CGFloat in CGFloat(0)..<needNumber{
let sprite = SKSpriteNode(texture: texture)
sprite.zPosition = -100.0
sprite.position = CGPoint(x: i*sprite.size.width, y: self.frame.size.height/2.0)
}
I am quite new at Swift, so this might be a pretty noob question but I would appreciate it if anyone could help :)
Range<T>, unlike CountableRange<T> isn't a sequence, because it's unclear how to iterate it. Add 1 every time? 0.1? 0.001?
You can use stride instead:
for i in stride(from: 0 as CGFloat, to: needNumber, by: +1 as CGFloat) { //...

Drawing dashed line in Sprite Kit using SKShapeNode

I fount this solution but I can't make it into swift code
This what I try
var pattern[2]:CGFloat; this
var dashed: CGPathRef = CGPathCreateCopyByDashingPath(CGPathCreateCopyByDashingPath(path, transform, phase, lengths, count);
var myShapeNode: SKShapeNode!;
var CGPathCreateCopyByDashingPath:CGPathRef;
This is how you can draw a dashed line in swift. You can change the parameters as you want.
let bezierPath = UIBezierPath()
let startPoint = CGPointMake(0, 250)
let endPoint = CGPointMake(450, 250)
bezierPath.moveToPoint(startPoint)
bezierPath.addLineToPoint(endPoint)
var pattern : [CGFloat] = [10.0, 10.0]
let dashed = CGPathCreateCopyByDashingPath (bezierPath.CGPath, nil, 0, pattern, 2)
var shapeNode = SKShapeNode(path: dashed)
shapeNode.position = CGPointMake(100, 100)
self.addChild(shapeNode)
In swift 4:
let square = SKShapeNode(rectOf: CGSize(width: 64, height: 64))
let pattern : [CGFloat] = [4.0, 4.0]
let dashed = square.path?.copy(dashingWithPhase: 1, lengths: pattern)
let shapeNode = SKShapeNode(path: dashed!)
shapeNode.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
shapeNode.fillColor = SKColor.clear
shapeNode.strokeColor = SKColor.red
shapeNode.lineWidth = 2
self.addChild(shapeNode)
For anyone looking to work out how to apply this same principal to an SKShapeNode like I was, here is an example. A rectangle with a blue dashed line.
import SpriteKit
import GameplayKit
let square = SKShapeNode(rectOfSize: CGSize(width: 64, height: 64))
let circle = SKShapeNode(circleOfRadius: 20.0)
var pattern : [CGFloat] = [2.0, 2.0]
let dashed = CGPathCreateCopyByDashingPath (square.path, nil, 0, pattern, 2)
var shapeNode = SKShapeNode(path: dashed!)
shapeNode.fillColor = UIColor.blueColor()
shapeNode.strokeColor = UIColor.blueColor()
Swift 5
if let path = path?.copy(dashingWithPhase: 1, lengths: [5, 5]) {
let line = SKShapeNode(path: path)
line.strokeColor = .white
self.addChild(line)
}
Adding to the solution provided by Mike Glukhov above, this is my solution:
func drawTrace(pointArray: Array<CGPoint>) {
if pointArray.count > 1 {
let pattern : [CGFloat] = [10.0, 10.0]
let path = CGMutablePath.init()
// start at the first point.
path.move(to: pointArray[0])
// now add all of the others.
for p in 1 ..< pointArray.count {
path.addLine(to: pointArray[p])
}
// create the dashed path.
let dashedPath = path.copy(dashingWithPhase: 1, lengths: pattern)
let dashName = "dash"
// now create the node
let line = SKShapeNode(path: dashedPath)
line.strokeColor = .white
line.name = dashName
if let parent = self.parent {
if let oldLine = parent.childNode(withName: dashName) {
oldLine.removeFromParent()
}
parent.addChild(line)
}
}
}

Apply vertical alpha gradient to UITableView

I'm new to iOS development and am trying to learn Swift. I'd like to apply a vertical alpha gradient to a UITableView, but am having some trouble.
Originally following this SO post, I did the following:
var gradientMaskLayer:CAGradientLayer = CAGradientLayer()
gradientMaskLayer.frame = myTableView.bounds
gradientMaskLayer.colors = [UIColor.clearColor().CGColor, UIColor.blackColor().CGColor]
gradientMaskLayer.locations = [0.0, 0.05]
myTableView.layer.mask = gradientMaskLayer
After getting the error Array element cannot be bridged to Objective-C and reading this SO post I modified the two arrays used:
var gradientMaskLayer:CAGradientLayer = CAGradientLayer()
var gradientMaskColors:NSArray = [UIColor.clearColor().CGColor, UIColor.blackColor().CGColor]
var gradientMaskLocations:NSArray = [0.0, 0.05]
gradientMaskLayer.frame = myTableView.bounds
gradientMaskLayer.colors = gradientMaskColors
gradientMaskLayer.locations = gradientMaskLocations
myTableView.layer.mask = gradientMaskLayer
And now get the error Value failed to bridge from Swift type to a Objective-C type
I'm struggling to find a solution. Can any lend some assistance?
You should mask the superview, not the view itself.
Here's an example:
let gradient = CAGradientLayer()
gradient.frame = tableView.superview?.bounds ?? .null
gradient.colors = [UIColor.clear.cgColor, UIColor.clear.cgColor, UIColor.black.cgColor, UIColor.black.cgColor, UIColor.clear.cgColor, UIColor.clear.cgColor]
gradient.locations = [0.0, 0.15, 0.25, 0.75, 0.85, 1.0]
tableView.superview?.layer.mask = gradient
tableView.backgroundColor = .clear
Result:
You can change the orientation by changing the startPoint and endpoint properties. The default values (vertically) are (0.5, 0.0) and (0.5, 1) respectively. Point (0,0) is the bottom-left corner of the layer and (1,1) is the top-right corner. For example, if you want to apply that mask horizontally instead of vertically, just do:
gradient.startPoint = .init(x: 0.0, y: 0.5)
gradient.endPoint = .init(x: 1.0, y: 0.5)
One more thing: if you're using AutoLayout, then you need to update the layer with the correct CGRect value. I usually override layoutSubviews() method to update it like gradient.frame = tableView.superview?.bounds ?? .null.
So I believe I have a solution to your problem, but I'm not sure that I fully understand it. The problem seems to arise when you try to create an implicitly unwrapped AnyObject array, containing only implicitly unwrapped Core Foundation types, i.e.:
let implicitlyUnwrappedCGColor:CGColor! = UIColor.clearColor().CGColor
let implicitlyUnwrappedAnyObjectArray:[AnyObject]! = [implicitlyUnwrappedCGColor]
gives the array element cannot be bridged to Objective-C error.
It feels like this must be a Swift compiler issue, particularly as the following, where the implicitly unwrapped CGColor is declared as an implicitly unwrapped AnyObject, seems to make the compiler happy again:
let implicitlyUnwrappedCGColor:AnyObject! = UIColor.clearColor().CGColor
let implicitlyUnwrappedAnyObjectArray:[AnyObject]! = [implicitlyUnwrappedCGColor]
as does sticking a standard Objective-C object into the array:
let implicitlyUnwrappedCGColor:CGColor! = UIColor.clearColor().CGColor
let uiColor = UIColor.clearColor()
let implicitlyUnwrappedAnyObjectArray:[AnyObject]! = [implicitlyUnwrappedCGColor, uiColor]
In any case, try the following as a solution to your issue:
var gradientMaskLayer:CAGradientLayer = CAGradientLayer()
gradientMaskLayer.frame = myTableView.bounds
gradientMaskLayer.colors = [UIColor.clearColor().CGColor!, UIColor.blackColor().CGColor!]
gradientMaskLayer.locations = [0.0, 0.05]
myTableView.layer.mask = gradientMaskLayer

Float is not convertible to CGFloat and CGFloat is not convertible to Float

I have a problem with swift on XCode 6 beta 4, is driving me nuts I'm in IOS 8 developing a game and I have follow a tutorial but I get this: Float is not convertible to CGFloat and then when I recast as CGFloat I get the other. Here is the code:
override func didMoveToView(view: SKView) {
/* Setup your scene here */
//physics
self.physicsWorld.gravity = CGVectorMake(0.0, -5.0)
// Bird
var birdTexture = SKTexture(imageNamed: "kirby")
birdTexture.filteringMode = SKTextureFilteringMode.Nearest
bird.setScale(0.5)
bird.position = CGPoint(x: self.frame.size.width * 0.35, y: self.frame.size.height * 0.6)
bird.physicsBody = SKPhysicsBody(circleOfRadius:bird.size.height/2)
bird.physicsBody.dynamic = true
bird.physicsBody.allowsRotation = false
self.addChild(bird)
//ground
ground.setScale(2.0)
ground.position = CGPointMake(self.size.width/2, ground.size.height/2)
ground.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(self.frame.size.width , ground.size.height))
ground.physicsBody.dynamic = false
self.addChild(ground)
//pipes
//create pipes
//^
//movement of the pipes
let distanceToMove = CGFloat(self.frame.size.width + 2.0 * pipeUp.texture.size().width)
let movePipe = SKAction.moveByX(-distanceToMove, y: CGFloat(0.0), duration: NSTimeInterval(0.01) * distanceToMove) <----- this line is the problem
}
What is going on, I move the line:
CGFloat(self.frame.size.width + 2.0 * pipeUp.texture.size().width)
I get the second error, then a recast:
Float(CGFloat(self.frame.size.width + 2.0 * pipeUp.texture.size().width))
or
Float(self.frame.size.width + 2.0 * pipeUp.texture.size().width)
gives me the first, so what do swift wants here, that is insane. Catch 22? Any help?
EDIT: I'm using a 13-inch mac late 2009, Intel Core 2 Duo, on mavericks OS X 10.9.4 (13E28) if any help. I saw something about the building options may affect the float types, but I do not know where are they.
This will be interpreted as a CGFloat and not as a NSTimeInterval as you cast and then multiply:
let movePipe = SKAction.moveByX(-distanceToMove, y: 0.0, duration: NSTimeInterval(0.01) * distanceToMove)
Try to multiply then cast to NSTimeInterval:
let movePipe = SKAction.moveByX(-distanceToMove, y: 0.0, duration: NSTimeInterval(0.01 * distanceToMove))
Also, as suggested already, you don't need to cast your distance. The following will work just fine:
let distanceToMove = self.frame.size.width + 2.0 * pipeUp.texture.size().width
Just make sure every operand has the same type. Literals (2.0) have always their type inferred. In your case, I see no problem because
let distanceToMove: CGFloat = self.frame.size.width + 2.0 * pipeUp.texture.size().width
has all the operands of type CGFloat so there is no need to cast at all.
On the next line, again make sure to use the correct types. You don't need to cast the literals:
SKAction.moveByX(-distanceToMove, y: 0.0, duration: 0.01 * NSTimeInterval(distanceToMove))