eddiekaiger / SwiftyAttributes

A Swifty API for attributed strings
MIT License
1.64k stars 83 forks source link

Instantiating an NSMutableAttributedString while importing SwiftyAttributes causes build error on Xcode 10 #29

Closed ketzusaka closed 6 years ago

ketzusaka commented 6 years ago

We've had this issue in our project preventing Xcode 10 compilation since the release. The error is:

Foundation.NSMutableAttributedString:11:12: note: found this candidate
    public init(string str: String, attributes attrs: [NSAttributedStringKey : Any]? = nil)
           ^
Foundation.NSAttributedString:19:12: note: found this candidate
    public init(string str: String, attributes attrs: [NSAttributedStringKey : Any]? = nil)

The usage was pretty basic, something like so:

let string = NSMutableAttributedString(string: "Hello World", attributes: [.strokeColor: UIColor.green])

After digging into it I discovered this doesn't happen unless we're importing SwiftyAttributes. If you duplicate the testInit_withStringAndAttributes test method, but replace the NSAttributedStrings with NSMutableAttributedStrings you'll get the same error when running the tests.

Attempting to use the convenience initializer on a NSMutableAttributedString results in the following error:

Cannot convert value of type '[Attribute]' to expected argument type '[NSAttributedStringKey : Any]?'

Taking out the convenience initializer on NSAttributedString, or giving the attributes parameter a different name resolves the issue.

It's likely that this is a bug with Swift. I'm not sure if you'd rather file a bug with them and see what happens, or resolve the issue within the library now. Changing the attributes parameter would be a breaking change and be cause for a major bump.

Let me know if you're going to take action on this at the library level if ya can, as it is preventing us from building on XC10 :)

Here's the diff w/ the fix and test that I experimented with:

diff --git a/SwiftyAttributes/Sources/common/NSAttributedString+SwiftyAttributes.swift b/SwiftyAttributes/Sources/common/NSAttributedString+SwiftyAttributes.swift
index 76a0b01..6c3a934 100644
--- a/SwiftyAttributes/Sources/common/NSAttributedString+SwiftyAttributes.swift
+++ b/SwiftyAttributes/Sources/common/NSAttributedString+SwiftyAttributes.swift
@@ -30,8 +30,8 @@ extension NSAttributedString {
      - parameter    str:            The string for the new attributed string.
      - parameter    attributes:     The attributes for the new attributed string.
      */
-    public convenience init(string str: String, attributes: [Attribute]) {
-        self.init(string: str, attributes: dictionary(from: attributes))
+    public convenience init(string str: String, swiftyAttributes attrs: [Attribute]) {
+        self.init(string: str, attributes: dictionary(from: attrs))
     }

     /**
diff --git a/SwiftyAttributesTests/NSAttributedString_Tests.swift b/SwiftyAttributesTests/NSAttributedString_Tests.swift
index 60947b3..79845e4 100644
--- a/SwiftyAttributesTests/NSAttributedString_Tests.swift
+++ b/SwiftyAttributesTests/NSAttributedString_Tests.swift
@@ -12,7 +12,7 @@ import SwiftyAttributes
 class NSAttributedString_Tests: XCTestCase {

     func testInit_withStringAndAttributes() {
-        let subject = NSAttributedString(string: "Hello World", attributes: [.strokeColor(.green), .strokeWidth(3)])
+        let subject = NSAttributedString(string: "Hello World", swiftyAttributes: [.strokeColor(.green), .strokeWidth(3)])
         #if swift(>=4.0)
             let expected = NSAttributedString(string: "Hello World", attributes: [.strokeColor: Color.green, .strokeWidth: 3])
         #else
diff --git a/SwiftyAttributesTests/NSMutableAttributedString_Tests.swift b/SwiftyAttributesTests/NSMutableAttributedString_Tests.swift
index 5577b2e..f95aba3 100644
--- a/SwiftyAttributesTests/NSMutableAttributedString_Tests.swift
+++ b/SwiftyAttributesTests/NSMutableAttributedString_Tests.swift
@@ -10,6 +10,16 @@ import XCTest
 import SwiftyAttributes

 class NSMutableAttributedString_Tests: XCTestCase {
+
+    func testInitMutable_withStringAndAttributes() {
+        let subject = NSMutableAttributedString(string: "Hello World", swiftyAttributes: [.strokeColor(.green), .strokeWidth(3)])
+        #if swift(>=4.0)
+        let expected = NSMutableAttributedString(string: "Hello World", attributes: [.strokeColor: Color.green, .strokeWidth: 3])
+        #else
+        let expected = NSMutableAttributedString(string: "Hello World", attributes: [NSStrokeColorAttributeName: Color.green, NSStrokeWidthAttributeName: 3])
+        #endif
+        XCTAssertEqual(subject, expected)
+    }

     func testAddAttributes_usingSwiftRange() {
         let subject = "Hello".withTextColor(.orange)
eddiekaiger commented 6 years ago

Thanks for pointing this out @ketzusaka. That's pretty strange that it only happens on NSMutableAttributedString 🤔. I may file a bug with Swift, but it would probably be good to change the parameter labels either way so it doesn't confuse the compiler. I'm down for the swiftyAttributes name change. Do you want to make the PR? Otherwise I can take care of it :)

ketzusaka commented 6 years ago

Yeah, I’ll open one once I get to the office :)

Thanks!

eddiekaiger commented 6 years ago

Fixed and released in v5.0.0 :)

wigl commented 5 years ago

I did the test in my FrameWork.

When I just add convenience init func in extension NSAttributedString, Xcode 10 compilation no error, The code is:

extension NSAttributedString {

    public convenience init(string str: String, attributes: [String]) {
        self.init(string: str, attributes: nil)
    }
}

But, when also add new func and parameter type is NSAttributedString.EnumerationOptions, Xcode 10 compilation error, The code is:

extension NSAttributedString {

    public convenience init(string str: String, attributes: [String]) {
        self.init(string: str, attributes: nil)
    }

    func test(options: NSAttributedString.EnumerationOptions) {

    }
}

I delete the options: NSAttributedString.EnumerationOptions, or use string Int or other type instead of NSAttributedString.EnumerationOptions, Xcode 10 compilation success.

eddiekaiger commented 5 years ago

@wigl I don't think this pertains to the issue above -- but what's the compilation error you're getting? I can't reproduce it on Xcode 10.

wigl commented 5 years ago

I forgot to tell you that the above code is inside the framework.

127 129
wigl commented 5 years ago

When the above extension is in the main project, there is no problem. @eddiekaiger