BaQiWL
BaQiWL

Reputation: 437

How can I convert the following code about CGContext into Swift3

Just like the headline ,I have some Objective-c code ,how can I use them in Swift3

CGContextSaveGState(context);
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CGContextTranslateCTM(context, 0, size.height);
CGContextScaleCTM(context, 1.0, -1.0);

CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, CGRectMake(0, 0, size.width, size.height));
NSMutableAttributedString *attri = [[NSMutableAttributedString alloc]initWithString:_text];
[attri addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:10] range:NSMakeRange(0, _text.length)];

CTFramesetterRef ctFramesetting = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attri);
CTFrameRef ctFrame = CTFramesetterCreateFrame(ctFramesetting, CFRangeMake(0, attri.length), path, NULL);
CTFrameDraw(ctFrame, context);

CFRelease(path);
CFRelease(ctFramesetting);
CFRelease(ctFrame);

Upvotes: 3

Views: 5009

Answers (2)

Oleh Zayats
Oleh Zayats

Reputation: 2443

Here's a clean Swift 3 version:

context.saveGState()
context.textMatrix = CGAffineTransform.identity
context.translateBy(x: 0, y: size.height)
context.scaleBy(x: 1.0, y: -1.0)

let path = CGMutablePath()
let rect = CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height)
path.addRect(rect, transform: .identity)

let attrString = NSMutableAttributedString(string: _text as String)
attrString.addAttribute(NSFontAttributeName,
                        value: UIFont.systemFont(ofSize: 10.0),
                        range: NSRange(location: 0, 
                                       length: _text.length))

let ctFramesetting = CTFramesetterCreateWithAttributedString(attrString)
let ctFrame = CTFramesetterCreateFrame(ctFramesetting, 
                                       CFRangeMake(0, attrString.length), 
                                       path, 
                                       nil)
CTFrameDraw(ctFrame, context)

I advise you not to use converters.

Why? With converters you'll

  • probably use variables where you need constants
  • bridge/cast values
  • explicitly unwrap optionals
  • break Swift style (this depends on what style you use actually, but still)
  • break language conventions

this means you'll get unstable/dirty code that you need to refactor

Upvotes: 4

Fahim
Fahim

Reputation: 3556

You can use something like the Objective-C to Swift Converter to get code like the following:

context.saveGState()
context.textMatrix = CGAffineTransform.identity
context.translateBy(x: 0, y: size.height)
context.scaleBy(x: 1.0, y: -1.0)
var path: CGMutablePathRef = CGMutablePath()
path.addRect(CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(size.width), height: CGFloat(size.height)), transform: .identity)
var attri = NSMutableAttributedString(string: _text)
attri.addAttribute(NSFontAttributeName, value: UIFont.systemFont(ofSize: CGFloat(10)), range: NSRange(location: 0, length: _text.length))
var ctFramesetting: CTFramesetterRef? = CTFramesetterCreateWithAttributedString((attri as? CFAttributedStringRef))
var ctFrame: CTFrameRef = CTFramesetterCreateFrame(ctFramesetting, CFRangeMake(0, attri.length), path, nil)
CTFrameDraw(ctFrame, context)

But I would suggest that you do learn the underlying principles of both Objective-C and Swift so that you can do this sort of conversion yourself instead of relying on others or an external tool :)

For example, the above is the code as it came out from the converter. However, if you were to do some clean up, it would look something like this:

guard let context = UIGraphicsGetCurrentContext() else {
    return
}
context.saveGState()
context.textMatrix = CGAffineTransform.identity
context.translateBy(x: 0, y: size.height)
context.scaleBy(x:1.0, y: -1.0)
let path = CGMutablePath()
path.addRect(CGRect(x:0, y:0, width:size.width, height:size.height), transform:.identity)
let attri = NSMutableAttributedString(string:_text as String)
attri.addAttribute(NSFontAttributeName, value: UIFont.systemFont(ofSize:10), range: NSRange(location: 0, length:_text.length))
let ctFramesetting = CTFramesetterCreateWithAttributedString(attri)
let ctFrame = CTFramesetterCreateFrame(ctFramesetting, CFRangeMake(0, attri.length), path, nil)
CTFrameDraw(ctFrame, context)

As you'll notice the following has to be added to get a CGContext instance:

guard let context = UIGraphicsGetCurrentContext() else {
    return
}

Also, some variables which were marked as mutable (or var) have been changed to immutable (or let) instances.

But that's not all there is to it. The above code assumes that _text is of type NSString. In order to use native Swift types, you should really change it to use String instead of NSString. Then the code changes to:

guard let context = UIGraphicsGetCurrentContext() else {
    return
}
context.saveGState()
context.textMatrix = CGAffineTransform.identity
context.translateBy(x: 0, y: size.height)
context.scaleBy(x:1.0, y: -1.0)
let path = CGMutablePath()
path.addRect(CGRect(x:0, y:0, width:size.width, height:size.height), transform:.identity)
let attri = NSMutableAttributedString(string:_text)
attri.addAttribute(NSFontAttributeName, value: UIFont.systemFont(ofSize:10), range: NSRange(location: 0, length:_text.characters.count))
let ctFramesetting = CTFramesetterCreateWithAttributedString(attri)
let ctFrame = CTFramesetterCreateFrame(ctFramesetting, CFRangeMake(0, attri.length), path, nil)
CTFrameDraw(ctFrame, context)

So, in order to convert the code to Swift 3 and to make it work, you do need to understand the differences between Swift and Objective-C.

Upvotes: -1

Related Questions