41

How would I do the following - passing two NSStringDrawing options as a function parameter in swift:

CGRect boundingRect = [string boundingRectWithSize:CGSizeMake(280.0, NSIntegerMax)
                                                      options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
                                                   attributes:options context:nil];
devmiles.com
  • 9,895
  • 5
  • 31
  • 47

8 Answers8

69

Edit: In Swift 3.0:

let options: NSStringDrawingOptions = [.usesLineFragmentOrigin, .usesFontLeading]

Edit: This is how you would use the options enum in Swift 2.0:

let options: NSStringDrawingOptions = [.UsesLineFragmentOrigin, .UsesFontLeading]

Edit: The issue has been resolved in iOS 8.3 SDK Beta 1 (12F5027d):

Modified NSStringDrawingOptions [struct]

  • From: enum NSStringDrawingOptions : Int
  • To: struct NSStringDrawingOptions : RawOptionSetType

You can now write:

let options : NSStringDrawingOptions = .UsesLineFragmentOrigin | .UsesFontLeading

After some research and and @Anton Tcholakov's "comment":

  1. If you're targeting OS X 10.10, this is as simple way to do it:

    let size = CGSize(width: 280, height: Int.max)
    let options : NSStringDrawingOptions = .UsesLineFragmentOrigin | .UsesFontLeading
    
    let boundingRect = string.bridgeToObjectiveC().boundingRectWithSize(size, options: options, attributes: attributes, context: nil)
    
  2. However, in iOS 8 SDK (in the current seed), there's a bug, where NSStringDrawingOptions is ported to Swift as enum : Int, instead of struct : RawOptionSet. You should send a bug report to Apple describing this serious problem.

Bogdan Farca
  • 3,856
  • 26
  • 38
akashivskyy
  • 44,342
  • 16
  • 106
  • 116
  • what sort of a drawing options that would return? ) there's only individual ones, not their combination, so the result of OR operation wouldn't pass the "type check" i guess – devmiles.com Jun 05 '14 at 16:28
  • 1
    Sorry, those should be 2 different options. But it wouldn't work neither. This is a bug. – akashivskyy Jun 05 '14 at 16:32
  • @devmiles.com Looks like a bug in iOS SDK, definetely. :( Check out my updated answer. – akashivskyy Jun 05 '14 at 16:52
  • I'm going to file a bug; anyone have an existing bug report number they want to share? – matt Aug 01 '14 at 03:56
  • Is this still an issue in the new Beta 5? – Mackey18 Aug 09 '14 at 07:19
  • 1
    Unfortunately yes. My bug report is still open. – akashivskyy Aug 09 '14 at 09:17
  • In Swift 1.2, NSStringDrawingOptions is declared as RawOptionSetType also on iOS. No need any workaround. – kishikawa katsumi Feb 11 '15 at 12:13
  • 1
    In Swift 2.0 this is no longer true. Now most of enums conform to `OptionSetType`, now you pass the enum values with the same syntax of arrays `[.UsesLineFragmentOrigin, .UsesFontLeading]`. See: http://stackoverflow.com/questions/30761996/swift-2-0-binary-operator-cannot-be-applied-to-two-uiusernotificationtype – GBF_Gabriel Sep 19 '15 at 17:11
21

Updated answer for Xcode 6.3:

in Xcode 6.3 Beta (Swift 1.2) this is finally fixed, you can do it now like this:

let boundingRect = "string".boundingRectWithSize(size, options: .UsesLineFragmentOrigin | .UsesFontLeading, attributes:nil, context:nil)

For old version:

It looks like a bug in current beta, for now I write Objective-C method and use it from Swift:

+ (NSStringDrawingOptions)combine:(NSStringDrawingOptions)option1 with:(NSStringDrawingOptions)option2
{
    return option1 | option2;
}

and call form Swift:

let boundingRect = "string".boundingRectWithSize(size, options: StringDrawingOptions.combine(.UsesLineFragmentOrigin, with: .UsesFontLeading), attributes:nil, context:nil)
Alexey Globchastyy
  • 2,175
  • 1
  • 15
  • 19
  • I wish I could upvote this twice. I would never have guessed that you could take an arbitrary integer from Objective-C, _call_ it an NSStringDrawingOptions, and get it past the Swift compiler. – matt Aug 01 '14 at 03:51
  • 1
    I ended up making a constant in an Objective-C file and just referencing it from Swift. Hopefully they fix this soon. – Sam Soffes Aug 12 '14 at 20:54
  • 7
    Amazingly, this bug still exists (iOS 8.1, Xcode 6.1GM2). – matt Oct 11 '14 at 18:34
  • Actually, iOS SDK 8.3, not Swift 1.2 fixed this. ;) – akashivskyy Feb 11 '15 at 13:56
7

Another solution, use unsafeBitCast.

Like below:

let options = unsafeBitCast(NSStringDrawingOptions.UsesLineFragmentOrigin.rawValue | 
                            NSStringDrawingOptions.UsesFontLeading.rawValue,
                            NSStringDrawingOptions.self)
kishikawa katsumi
  • 10,418
  • 1
  • 41
  • 53
3

in swift 2.0 that will be something like

theStringDrawingOptions = [NSStringDrawingOptions.UsesLineFragmentOrigin,
                           NSStringDrawingOptions.UsesFontLeading]

see lecture wwdc 2015 -> 106_hd_whats_new_in_swift in 6 min

elp
  • 8,021
  • 7
  • 61
  • 120
myUser
  • 537
  • 5
  • 9
3

In Swift 2.1 we may use,

calculatedRect = (text as NSString).boundingRectWithSize(bounds.size, options: NSStringDrawingOptions([.UsesLineFragmentOrigin, .UsesFontLeading]), attributes: [NSFontAttributeName : font], context: nil)

to pass multiple enum values for a parameter.

jarora
  • 5,384
  • 2
  • 34
  • 46
1

Can't seem to comment to akashivskyy's post (not got 50+ reputation), but this seems to work on my end:

import Cocoa

let drawingOpts : NSStringDrawingOptions = .UsesLineFragmentOrigin | .UsesFontLeading
let boundingRect = "test".bridgeToObjectiveC().boundingRectWithSize(CGSize(width: 280, height: Int.max), options: drawingOpts, attributes: nil)

Also if I Cmd+click NSStringDrawingOptions I see it as inheriting from RawOptionSet.

Anton Tcholakov
  • 3,710
  • 1
  • 12
  • 10
0

Swift supports C's bitwise OR operator, but the enum's values are now in a specific scope instead of simply being global symbols:

let boundingRect = "fpp".boundingRectWithSize(CGSizeMake(280.0, CGFloat.max),
    options:NSStringDrawingOptions.UsesLineFragmentOrigin | NSStringDrawingOptions.UsesFontLeading,
    attributes:nil, context:nil)
Sam Soffes
  • 14,831
  • 9
  • 76
  • 80
Bill
  • 44,502
  • 24
  • 122
  • 213
0

In swift 4.0+ we can pass multiple options like this, its working for me

let options = NSStringDrawingOptions(rawValue: NSStringDrawingOptions.usesLineFragmentOrigin.rawValue | NSStringDrawingOptions.usesFontLeading.rawValue)

let boundingRect = string._bridgeToObjectiveC().boundingRect(with: CGSize(width: 280, height: Int.max), options: options, attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 19.0)], context: nil)
Dipak
  • 2,263
  • 1
  • 21
  • 27