2

I have very weird problem with below code.

extension String {
        func height(withConstrainedWidth width: CGFloat, font: UIFont) -> CGFloat {
            let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude)
            let boundingBox = boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font: font], context: nil)

            return ceil(boundingBox.height)
        }
}

It always throwing below compiler error.

enter image description here

But if I use self.boundingRect then it compile successfully and run the application but after launched app on simulator it automatically revert to again boundingRect (Removing self).

So everytime I need to add self. to execute app.

Sunil Targe
  • 7,251
  • 5
  • 49
  • 80

1 Answers1

6

It is because the boundingRect is NSString's extension method

extension NSString {

    @available(iOS 7.0, *)
    open func draw(with rect: CGRect, options: NSStringDrawingOptions = [], attributes: [NSAttributedStringKey : Any]? = nil, context: NSStringDrawingContext?)

    @available(iOS 7.0, *)
    open func boundingRect(with size: CGSize, options: NSStringDrawingOptions = [], attributes: [NSAttributedStringKey : Any]? = nil, context: NSStringDrawingContext?) -> CGRect
}

So if you change String to NSString extension it will work

extension NSString {
    func height(withConstrainedWidth width: CGFloat, font: UIFont) -> CGFloat {
        let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude)
        
        let boundingBox = boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font: font], context: nil)
        
        return ceil(boundingBox.height)
    }
}

EDIT From Swift Team

https://bugs.swift.org/browse/SR-8408

The code in the compiler that says "NSString's members show up on String values" is specifically looking for member syntax, i.e. "foo.bar"—or in this case, "self.bar". It probably shouldn't have been written that way, but it was.

I think we'd still recommend being explicit here, even if it's ugly: (self as NSString).boundingRect(…) or let nsSelf = self as NSString; nsSelf.boundingRect(…).

Community
  • 1
  • 1
Prashant Tukadiya
  • 15,838
  • 4
  • 62
  • 98