SKSpriteNode as Return error - Swift 2 - xcode

I am trying to swap out a basic ball for an image of a ball. I am going through a tutorial and don't know how to fix this. This code is in a file Ball.swift as a function and would like to try avoid redwiring all of the code. Thanks in advance!
Error: Cannot convert return of the type Ball.Type to return type "Ball"
static func make()-> Ball {
var Ball = SKSpriteNode()
Ball = SKSpriteNode(imageNamed: "blueball")
//let ball = Ball(circleOfRadius: 30)
Ball.physicsBody = SKPhysicsBody(circleOfRadius: Ball.frame.size.width / 2)
Ball.physicsBody!.dynamic = true
Ball.physicsBody!.allowsRotation = true //thi was false
Ball.userData = NSMutableDictionary()
// self.addChild(Ball)
return self // error
}

Ball is the name of a variable, and not a type.
The function should return an SKSpriteNode which is the class of the ball object. You can also use type inference to avoid having to declare the type. Altogether, it would look like this:
static func make() -> SKSpriteNode {
let ball = SKSpriteNode(imageNamed: "blueball")
// Set physics body ...
return ball
}
Tip: Variables are usually named with a lowercase letter, e.g. var ball = ..., and not var Ball = .... This makes it easier to differentiate between variables and types.

Related

Make 2 contradictory methods work in drawRect

I'm writing an app building elements consisting of CGPoints. I have 2 buttons: makeRectangle and makeTriangle. For building/drawing stage I use three methods for rectangle and three methods for triangle inside drawRect.
I'm stuck with my code in drawRect. In if-else-statement each method swaps the building/drawing scheme for previous element every time a button pressed.
If I already have built rectangle and then I click makeTriangle button, I get new triangle but my rectangle turns into triangle with one unconnected point.
Is there a workaround or I shouldn't use drawRect method?
Here's an SO post on the drawRect topic: To drawRect or not to drawRect
Element declaration:
enum Element {
case point1(point: CGPoint)
case point2(point: CGPoint)
case point3(point: CGPoint)
case point4(point: CGPoint)
func coord() -> [CGPoint] {
switch self {
case .point1(let point): return [point]
case .point2(let point): return [point]
case .point3(let point): return [point]
case .point4(let point): return [point]
}
}
func buildQuadPath(path: CGMutablePath) {
switch self {
case .point1(let point): CGPathMoveToPoint(path, nil, point.x, point.y)
case .point2(let point): CGPathAddLineToPoint(path, nil, point.x, point.y)
case .point3(let point): CGPathAddLineToPoint(path, nil, point.x, point.y)
case .point4(let point): CGPathAddLineToPoint(path, nil, point.x, point.y)
CGPathCloseSubpath(path)
}
}
func buildTriPath(path: CGMutablePath) {
switch self {
case .point1(let point): CGPathMoveToPoint(path, nil, point.x, point.y)
case .point2(let point): CGPathAddLineToPoint(path, nil, point.x, point.y)
case .point3(let point): CGPathAddLineToPoint(path, nil, point.x, point.y)
default:
CGPathCloseSubpath(path)
}
}
}
Methods for building and drawing triangle and rectangle:
func buildTriPath() -> CGMutablePath {
let path = CGPathCreateMutable()
_ = array.map { $0.buildTriPath(path) }
return path
}
func drawTriPath() {
let path = buildTriPath()
GraphicsState {
CGContextAddPath(self.currentContext, path)
CGContextStrokePath(self.currentContext)
}
}
func drawTriFill() {
let fill = buildTriPath()
GraphicsState {
CGContextAddPath(self.currentContext, fill)
CGContextFillPath(self.currentContext)
}
}
///////////////////////////////////////////////////////
func buildQuadPath() -> CGMutablePath {
let path = CGPathCreateMutable()
_ = array.map { $0.buildQuadPath(path) }
return path
}
func drawQuadPath() {
let path = buildQuadPath()
GraphicsState {
CGContextAddPath(self.currentContext, path)
CGContextStrokePath(self.currentContext)
}
}
func drawQuadFill() {
let fill = buildQuadPath()
GraphicsState {
CGContextAddPath(self.currentContext, fill)
CGContextFillPath(self.currentContext)
}
}
Two variables help determine whether button is pressed:
var squareB: Int = 0
var triangleB: Int = 0
#IBAction func makeTriangle(sender: AnyObject?) {
....................
....................
triangleB += 1
squareB = 0
}
#IBAction func makeRectangle(sender: AnyObject?) {
....................
....................
triangleB = 0
squareB += 1
}
drawRect method:
override func drawRect(dirtyRect: NSRect) {
super.drawRect(dirtyRect)
drawBG()
GraphicsState { self.drawMyPoints() }
if squareB >= 1 && triangleB == 0 {
buildQuadPath()
drawQuadPath()
drawQuadFill()
needsDisplay = true
}
else if triangleB >= 1 && squareB == 0 {
buildTriPath()
drawTriPath()
drawTriFill()
needsDisplay = true
}
drawBorder()
}
...and at last a Context.swift file:
import Cocoa
import CoreGraphics
extension NSView {
var currentContext : CGContext? {
get {
let unsafeContextPointer = NSGraphicsContext.currentContext()?.graphicsPort
if let contextPointer = unsafeContextPointer {
let opaquePointer = COpaquePointer(contextPointer)
let context: CGContextRef = Unmanaged.fromOpaque(opaquePointer).takeUnretainedValue()
return context }
else { return nil }
}
}
func GraphicsState(drawStuff: () -> Void) {
CGContextSaveGState(currentContext)
drawStuff()
CGContextRestoreGState(currentContext)
}
}
//the end of code
Okay, since I could use the practice I created an example project to show what vikingosegundo and I mean.
Here's the gist of it:
For this example I kept all relevant code except the adding and removing of shapes in a GHShapeDemoView.
I used structs to define the shapes, but treat them as one "unit" of data that is handled during drawing, adding to the view, etc. All shapes are kept in an array and during drawing that is iterated and all found shapes are drawn using a simple NSBezierPath.
For simplicity's sake I just chose some random fixed points for each shape, in a real project that would obviously be determined in another way (I was too lazy to add input fields...).
Even here there are a lot of ways to refactor (probably). For example, one could even make each shape a class of its own (or use one class for shapes in general). Maybe even a subclass of NSView, that would then result in the "drawing area" itself not be a custom view, but a normal one and on button presses relevant shape views would be added as subviews. That would then probably also get rid of all this points-calculating stuff (mostly).
In a real project I would probably have gone for shapes as layer subclasses that I then add to the subview. I'm no expert, but I think that might have performance benefits depending on how many shapes there are and whether or not I would animate them.
(Obviously the highest performance would probably be gained from using OpenGL ES or something, but I have no clue about that and that's far beyond the scope of this question).
I hope this provides you with a good starting point to work on your drawing. As stated above I would strongly suggest restructuring your project in a similar way to properly define a flow of what you draw and how you draw it. If you somehow must rely on keeping points data in enums or structs or something, write adequate mappers to your drawing data structure.
if (makeTriangle != nil) { and if (makeRectangle != nil) { doesnt make much sense. according to your comment, makerRectangle and makeTriangle are buttons. By your statements you are checking their existence — and we can assume they always exists — the first if-clause will always be executed.
what you want instead: create method that will be executed by the buttons. Each of this method will set either a combination of bool values or a single enum value and then tell the view to redraw by calling setNeedsDisplay().
Here is a code written by Gero:
This code works well with Swift 2.2.
//
// GHShapeDemoView.swift
// GHShapeDrawingExample
//
// Created by Gero Herkenrath on 21/10/2016.
// Copyright © 2016 Gero Herkenrath. All rights reserved.
//
import Cocoa
class GHShapeDemoView: NSView {
struct Shape {
var p1:CGPoint = NSMakePoint(0.0, 0.0)
var p2:CGPoint = NSMakePoint(0.0, 0.0)
var p3:CGPoint = NSMakePoint(0.0, 0.0)
var p4:CGPoint?
}
var shapes:[Shape] = []
override internal var flipped: Bool {
return true
}
override func drawRect(dirtyRect: NSRect) {
super.drawRect(dirtyRect)
NSColor.whiteColor().setFill()
let updatedRect = NSBezierPath.init(rect: dirtyRect)
updatedRect.fill()
for shape in shapes {
drawShape(shape)
}
}
func drawShape(shape:Shape) {
let shapePath = NSBezierPath()
shapePath.moveToPoint(shape.p1)
shapePath.lineToPoint(shape.p2)
shapePath.lineToPoint(shape.p3)
if let lastPoint = shape.p4 {
shapePath.lineToPoint(lastPoint)
}
shapePath.closePath()
NSColor.blackColor().setStroke()
shapePath.stroke()
}
func addTrapezoid(p1:NSPoint, p2:NSPoint, p3:NSPoint, p4:NSPoint) {
var shape = Shape()
shape.p1 = p1
shape.p2 = p2
shape.p3 = p3
shape.p4 = p4
shapes.append(shape)
}
func addTriangle(p1:NSPoint, p2:NSPoint, p3:NSPoint) {
var shape = Shape()
shape.p1 = p1
shape.p2 = p2
shape.p3 = p3
shapes.append(shape)
}
func removeShapeAt(index:Int) {
if index < shapes.count {
shapes.removeAtIndex(index)
}
}
}
/////////////////////////////////////////////////
//
// ViewController.swift
// GHShapeDrawingExample
//
// Created by Gero Herkenrath on 21/10/2016.
// Copyright © 2016 Gero Herkenrath. All rights reserved.
//
import Cocoa
class ViewController: NSViewController {
override func viewDidLoad() {
if #available(OSX 10.10, *) {
super.viewDidLoad()
}
else {
// Fallback on earlier versions
}
// Do any additional setup after loading the view.
}
override var representedObject: AnyObject? {
didSet {
// Update the view, if already loaded.
}
}
// first Shape
let pointA1 = NSMakePoint(115.0, 10.0)
let pointA2 = NSMakePoint(140.0, 10.0)
let pointA3 = NSMakePoint(150.0, 40.0)
let pointA4 = NSMakePoint(110.0, 40.0)
// second Shape
let pointB1 = NSMakePoint(230.0, 10.0)
let pointB2 = NSMakePoint(260.0, 40.0)
let pointB3 = NSMakePoint(200.0, 40.0)
// thirdShape
let pointC1 = NSMakePoint(115.0, 110.0)
let pointC2 = NSMakePoint(140.0, 110.0)
let pointC3 = NSMakePoint(150.0, 140.0)
let pointC4 = NSMakePoint(110.0, 140.0)
#IBOutlet weak var shapeHolderView: GHShapeDemoView!
#IBAction func newTrapezoid(sender: AnyObject) {
if shapeHolderView.shapes.count < 1 {
shapeHolderView.addTrapezoid(pointA1, p2: pointA2, p3: pointA3, p4: pointA4)
}
else {
shapeHolderView.addTrapezoid(pointC1, p2: pointC2, p3: pointC3, p4: pointC4)
}
shapeHolderView.setNeedsDisplayInRect(shapeHolderView.bounds)
}
#IBAction func newTriangle(sender: AnyObject) {
shapeHolderView.addTriangle(pointB1, p2: pointB2, p3: pointB3)
shapeHolderView.setNeedsDisplayInRect(shapeHolderView.bounds)
}
#IBAction func removeLastShape(sender: AnyObject) {
if shapeHolderView.shapes.count > 0 {
shapeHolderView.removeShapeAt(shapeHolderView.shapes.count - 1)
shapeHolderView.setNeedsDisplayInRect(shapeHolderView.bounds)
}
}
}

XCode 7: Copy Layoutattributes

I'm getting the warning "This is likely occurring because the flow layout subclass MyApp.MenuFlowLayout is modifying attributes returned by UICollectionViewFlowLayout without copying them". How can I copy this in Swift?
override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
if let array = super.layoutAttributesForElementsInRect(rect) as [UICollectionViewLayoutAttributes]? {
var visibleRect = CGRectZero
visibleRect.origin = (self.collectionView?.contentOffset)!
visibleRect.size = (self.collectionView?.bounds.size)!
let activeDisatance : CGFloat = visibleRect.size.width / 2
let zoomFactor : CGFloat = 0.15
for attributes in array{
if CGRectIntersectsRect(attributes.frame, visibleRect){
let distance = CGRectGetMidX(visibleRect) - attributes.center.x
let normalizedDistance = distance / activeDisatance
if abs(distance) < activeDisatance{
let zoom = 1 + zoomFactor * (1 - abs(normalizedDistance))
attributes.transform3D = CATransform3DMakeScale(zoom, zoom, 1.0)
attributes.zIndex = 1
}
}
}
return array
}
return super.layoutAttributesForElementsInRect(rect)
}
Collections in Swift are value types, that's the reason why they don't have a copy() method. So when you are calling
array = super.layoutAttributesForElementsInRect(rect) as [UICollectionViewLayoutAttributes]?
it already creates a copy of the super layout attributes array and stores it in array
The problem is not that the array has not been copied, the problem is, that you are changing the UICollectionViewLayoutAttributes inside the array without copying them first.
To avoid this error message you can do something like this:
override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let attributes = super.layoutAttributesForElementsInRect(rect)
var attributesCopy = [UICollectionViewLayoutAttributes]()
for itemAttributes in attributes! {
let itemAttributesCopy = itemAttributes.copy() as! UICollectionViewLayoutAttributes
// add the changes to the itemAttributesCopy
attributesCopy.append(itemAttributesCopy)
}
return attributesCopy
}

updating score variable from a different class

I'm trying to get my score to carry over to a new scene after the game is over and when this happens the score is coming out at 0. The score is set to 0 in my PlayScene as a default but I need it to read what the score is in ScoreScene when the PlayScene is over. Help Please!!
import SpriteKit
import AVFoundation
class PlayScene: SKScene, SKPhysicsContactDelegate {
let scoreText = SKLabelNode(fontNamed: "System-Bold")
var score = 0
override func didMoveToView(view: SKView) {
self.scoreText.text = "0"
self.scoreText.fontSize = 42
self.scoreText.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMaxY(self.frame) / 1.075)
func didBeginContact(contact:SKPhysicsContact) {
var scene = ScoreScene(size: self.size)
let skView = self.view as SKView!
skView.ignoresSiblingOrder = true
scene.scaleMode = .ResizeFill
scene.size = skView.bounds.size
skView.presentScene(scene)
func blockRunner() {
for(block, blockStatus) in self.blockStatuses {
var thisBlock = self.childNodeWithName(block)
if blockStatus.shouldRunBlock() {
blockStatus.timeGapForNextRun = random()
blockStatus.currentInterval = 0
blockStatus.isRunning = true
}
if blockStatus.isRunning {
if thisBlock!.position.x > blockMaxX {
thisBlock!.position.x -= CGFloat(self.groundSpeed)
}else {
thisBlock!.position.x = self.origBlockPositionX
blockStatus.isRunning = false
self.score++
if ((self.score % 10) == 0) {
self.groundSpeed++
}
self.scoreText.text = String(self.score)
}
}else {
blockStatus.currentInterval++
}
}
}
and Now when the game is over it switches to Score scene which is below
class ScoreScene: SKScene {
var playScene = PlayScene()
let scoreText = SKLabelNode(fontNamed: "System-Bold")
override func didMoveToView(view: SKView) {
self.scoreText.text = "score: \(playScene.score)"
self.scoreText.fontSize = 42
self.scoreText.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMaxY(self.frame) / 1.075)
You need to create a separate model to hold your data so you can access it from different parts of the app, I normally use a singleton approach so I can create the class only once and access its values anytime I need. What I would do:
create a new class player that keep the details about the player like
score make this class a singleton use this class to populate the
score value through all the scenes of the game
More details about design patterns in swift here (including singleton)
You will find a lot of code demos for singleton in here

sometimes sprites will not bounce off the physics boundary

I'm beginning a new game and have a weird problem right off the bat. In my didMoveToView function I have the following to put a bounds on my sprites within the frame(whole screen)
self.physicsBody=SKPhysicsBody(edgeLoopFromRect: self.frame)
The following code adds an SKSpriteNode at the touch point and adds a rotatebyangle action with a repeat forever
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
/* Called when a touch begins */
for touch: AnyObject in touches {
let location = touch.locationInNode(balloonWorld)
let nodeAtPoint = self.nodeAtPoint(location)
if(nodeAtPoint.name == nil) {
let location = touch.locationInNode(self)
let randNum:Int = Int.random(min: 0, max: 7)
var stringColor:String = (balloonColors.objectAtIndex(randNum) as String)
stringColor = stringColor.stringByReplacingOccurrencesOfString("face",
withString :"")
let sprite = Balloon(theColor:stringColor)
//let spriteFileName:String = balloonColors.objectAtIndex(randNum) as String
//let sprite = SKSpriteNode(imageNamed:spriteFileName)
sprite.xScale = 0.5
sprite.yScale = 0.5
sprite.position = location
sprite.zPosition = SceneLevel.hero.rawValue
balloonWorld!.addChild(sprite)
let action = SKAction.rotateByAngle(CGFloat(-M_PI), duration:1)
sprite.runAction(SKAction.repeatActionForever(action))
} else {
nodeAtPoint.removeFromParent()
println(nodeAtPoint.name)
}
}
}
I've setup balloonWorld as follows:
balloonWorld = SKNode()
self.addChild(balloonWorld!)
My problem is that sometimes the balloon sprites will not bounce off the edge, but just keep going thru the edge never to be seen again.
Any suggestions?
Thanks,
Ken
per request here's the code for setting up the physics bodies
balloon:
class Balloon: SKNode {
// properties
var myColor:String?
var objectSprite:SKSpriteNode?
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
init(theColor:String){
super.init()
self.myColor=theColor
let imageFileName = "\(theColor)face"
let objectSprite:SKSpriteNode = SKSpriteNode(imageNamed:imageFileName)
objectSprite.physicsBody = SKPhysicsBody(circleOfRadius: objectSprite.size.height / 2.0)
objectSprite.physicsBody?.affectedByGravity = true
objectSprite.name = theColor + " balloon"
addChild(objectSprite)
}
}
I didn't set up a physics body on the boundary as I though all I needed was the line self.physicsBody = SKPhysicsBody(edgeLoopFrom Rect : self:frame) since the boundary has the same frame.
I tried adding the following, but that did not change the behavior:
let borderShape=SKShapeNode(rect: CGRectMake(self.frame.origin.x+2, self.frame.origin.y+2, self.frame.size.width-4, self.frame.size.height-4))
borderShape.fillColor=SKColor.clearColor()
borderShape.strokeColor=SKColor.blackColor()
borderShape.lineWidth=1
borderShape.physicsBody?.categoryBitMask=BodyType.boundary.rawValue
borderShape.zPosition=SceneLevel.border.rawValue
borderShape.physicsBody=SKPhysicsBody(edgeLoopFromRect: borderShape.frame)
balloonWorld!.addChild(borderShape)
Create an enum to differentiate the two types of sprites:
enum ColliderType {
case sprite1 = 1
case sprite2 = 2
}
You need to add a contact and collision bit mask like so:
borderShape.physicsBody?.contactTestBitMask = ColliderType.sprite2.rawValue
Also add a collisionBitMask:
borderShape.physicsBody?.collisionBitMask = ColliderType.sprite2.rawValue
Do the same for sprite2 and set it's collisionBitMask and it's contactTestBitMask to be the rawValue of sprite1. Make sure you set this class to be the contactDelegate so you receive a warning though a function that will notify you when two objects have collided:
self.physicsWorld?.contactDelegate = self
func didBeginContact(contact: SKPhysicsContact) {
[handle the contact however you would like to here]
}
I hope this helps!
LearnCocos2D(Steffen Itterheim) pointed me in the right direction in his comment. I was using moveTo/moveBy and the physics engine would not properly handle that. Once I simply made the moves based on impulses everything worked fine.
Thanks Steffen

set and create paragraph style in swift

I am trying to port an objective C method to draw text in a PDF context to Swift.
I could convert most of the code, but the following lines are giving me a problem.
Some help in the conversion would be welcome.
Here the Objective C code:
-(void)drawText:(NSString *)textToDraw context:(CGContextRef)myPDFContext textcolor:(NSColor *)textcolor textfont:(NSFont*)textfont textbox:(CGRect)boxsize pagesize:(CGSize)pageSize {
// .........
// create paragraph style and assign text alignment to it
CTTextAlignment alignment = kCTJustifiedTextAlignment;
CTParagraphStyleSetting _settings[] = { {kCTParagraphStyleSpecifierAlignment, sizeof(alignment), &alignment} };
CTParagraphStyleRef paragraphStyle = CTParagraphStyleCreate(_settings, sizeof(_settings) / sizeof(_settings[0]));
// set paragraph style attribute
CFAttributedStringSetAttribute(attrStr, CFRangeMake(0, CFAttributedStringGetLength(attrStr)), kCTParagraphStyleAttributeName, paragraphStyle);
// .........
}
// The following lines are my try in Swift, but this gives errors:
func DrawText(textToDraw:String, myPDFContext:CGContextRef, textcolor:NSColor, textfont:NSFont, boxsize:CGRect, pagesize:CGSize) {
var alignment = CTTextAlignment.TextAlignmentLeft
let alignmentSetting = CTParagraphStyleSetting(spec: CTParagraphStyleSpecifier.Alignment, valueSize: sizeof(alignment), value: &alignment)
let paragraphStyle = CTParagraphStyleCreate(alignmentSetting, 1)
//.......
If this is solved I could post the complete method in Swift.
I think this does it:
var alignment = CTTextAlignment.TextAlignmentLeft
let alignmentSetting = [CTParagraphStyleSetting(spec: .Alignment, valueSize: UInt(sizeofValue(alignment)), value: &alignment)]
let paragraphStyle = CTParagraphStyleCreate(alignmentSetting, 1)
CFAttributedStringSetAttribute(attrStr, CFRangeMake(0, CFAttributedStringGetLength(attrStr)), kCTParagraphStyleAttributeName, paragraphStyle)
I made the following modifications:
I changed sizeof(alignment) to UInt(sizeofValue(alignment)) because sizeof in Swift only takes a type (such as sizeof(Int)). The UInt() is a constructor that turns the Int returned by sizeofValue into the UInt needed by this call.
I make alignmentSetting into an array so that it could be passed to an UnsafePointer of that type. This also better matches the original version.
I changed CTParagraphStyleSpecifier.Alignment to just .Alignment since the first part isn't needed since spec is of type CTParagraphStyleSpecifier.
The hardcoded 1 is OK in this case because you are passing just one value, but the more general solution would be to do:
let paragraphStyle = CTParagraphStyleCreate(alignmentSetting, UInt(alignmentSetting.count))
Here the full working method based on the corrections and help.
func drawText(textToDraw:String, myPDFContext:CGContextRef, textcolor:NSColor, textfont:NSFont, boxsize:CGRect, pagesize:CGSize) {
let _font = NSFont(name:textfont.fontName, size:textfont.pointSize )
if (_font == nil) {
println("Font [\(textfont)] does not exist")
return
}
let myBoxWidth = boxsize.size.width
let myBoxHeight = boxsize.size.height
let myBoxxpos = boxsize.origin.x
let myBoxypos = boxsize.origin.y
let frameRect = CGRectMake(myBoxxpos, myBoxypos,myBoxWidth,myBoxHeight);
let framePath = CGPathCreateMutable()
CGPathAddRect(framePath, nil, frameRect);
// create attributed string
let attrStr = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0);
CFAttributedStringReplaceString (attrStr, CFRangeMake(0, 0), textToDraw);
// create font
let font = CTFontCreateWithName(textfont.fontName, textfont.pointSize, nil);
var alignment = CTTextAlignment.TextAlignmentLeft
let alignmentSetting = [CTParagraphStyleSetting(spec: .Alignment, valueSize: UInt(sizeofValue(alignment)), value: &alignment)]
//let paragraphStyle = CTParagraphStyleCreate(alignmentSetting, 1)
let paragraphStyle = CTParagraphStyleCreate(alignmentSetting, UInt(alignmentSetting.count))
CFAttributedStringSetAttribute(attrStr, CFRangeMake(0, CFAttributedStringGetLength(attrStr)), kCTParagraphStyleAttributeName, paragraphStyle)
// set font attribute
CFAttributedStringSetAttribute(attrStr, CFRangeMake(0, CFAttributedStringGetLength(attrStr)), kCTFontAttributeName, font);
// set color attribute
CFAttributedStringSetAttribute(attrStr,CFRangeMake(0, CFAttributedStringGetLength(attrStr)), kCTForegroundColorAttributeName,textcolor.CGColor);
// Prepare the text using a Core Text Framesetter.
let framesetter = CTFramesetterCreateWithAttributedString(attrStr);
// Get the frame that will do the rendering.
let currentRange = CFRangeMake(0, 0);
let frameRef = CTFramesetterCreateFrame(framesetter, currentRange, framePath, nil);
// Put the text matrix into a known state. This ensures
// that no old scaling factors are left in place.
CGContextSetTextMatrix(myPDFContext, CGAffineTransformIdentity);
// Draw the frame.
CTFrameDraw(frameRef, myPDFContext);
}

Resources