From b96c19c3504f9f3e0fc8e2c5acf69e2c03271852 Mon Sep 17 00:00:00 2001 From: "Tanner W. Stokes" Date: Fri, 8 Sep 2023 16:26:01 -0400 Subject: [PATCH 1/3] Use NSString methods due to iOS 17 crash. --- .../NSAttributedString+ParagraphRange.swift | 30 +++++++------------ 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/Aztec/Classes/Extensions/NSAttributedString+ParagraphRange.swift b/Aztec/Classes/Extensions/NSAttributedString+ParagraphRange.swift index bb7ef206a..22c4c79d9 100644 --- a/Aztec/Classes/Extensions/NSAttributedString+ParagraphRange.swift +++ b/Aztec/Classes/Extensions/NSAttributedString+ParagraphRange.swift @@ -22,14 +22,13 @@ extension NSAttributedString { /// func paragraphRanges(intersecting range: NSRange, includeParagraphSeparator: Bool = true) -> [NSRange] { var paragraphRanges = [NSRange]() - let swiftRange = string.range(fromUTF16NSRange: range) - let paragraphsRange = string.paragraphRange(for: swiftRange) - - string.enumerateSubstrings(in: paragraphsRange, options: .byParagraphs) { [unowned self] (substring, substringRange, enclosingRange, stop) in + let paragraphsRange = foundationString.paragraphRange(for: range) + + foundationString.enumerateSubstrings(in: paragraphsRange, options: .byParagraphs) { (substring, substringRange, enclosingRange, stop) in let paragraphRange = includeParagraphSeparator ? enclosingRange : substringRange - paragraphRanges.append(self.string.utf16NSRange(from: paragraphRange)) + paragraphRanges.append(paragraphRange) } - + return paragraphRanges } @@ -44,16 +43,12 @@ extension NSAttributedString { /// func paragraphRanges(intersecting range: NSRange) -> ([ParagraphRange]) { var paragraphRanges = [ParagraphRange]() - let swiftRange = string.range(fromUTF16NSRange: range) - let paragraphsRange = string.paragraphRange(for: swiftRange) - - string.enumerateSubstrings(in: paragraphsRange, options: .byParagraphs) { [unowned self] (substring, substringRange, enclosingRange, stop) in - let substringNSRange = self.string.utf16NSRange(from: substringRange) - let enclosingNSRange = self.string.utf16NSRange(from: enclosingRange) - - paragraphRanges.append((substringNSRange, enclosingNSRange)) + let paragraphsRange = foundationString.paragraphRange(for: range) + + foundationString.enumerateSubstrings(in: paragraphsRange, options: .byParagraphs) { (substring, substringRange, enclosingRange, stop) in + paragraphRanges.append((substringRange, enclosingRange)) } - + return paragraphRanges } @@ -62,10 +57,7 @@ extension NSAttributedString { /// This is an attributed string wrapper for `NSString.paragraphRangeForRange()` /// func paragraphRange(for range: NSRange) -> NSRange { - let swiftRange = string.range(fromUTF16NSRange: range) - let outRange = string.paragraphRange(for: swiftRange) - - return string.utf16NSRange(from: outRange) + return foundationString.paragraphRange(for: range) } func paragraphRange(for attachment: NSTextAttachment) -> NSRange { From 1bd24f9415d3ee550cb6d6d88c01458b8cc56300 Mon Sep 17 00:00:00 2001 From: "Tanner W. Stokes" Date: Tue, 12 Sep 2023 12:34:55 -0400 Subject: [PATCH 2/3] Add tests for paragraphRange crash. --- ...SAttributedStringParagraphRangeTests.swift | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/AztecTests/Extensions/NSAttributedStringParagraphRangeTests.swift b/AztecTests/Extensions/NSAttributedStringParagraphRangeTests.swift index ac8b3df2c..be5701e9b 100644 --- a/AztecTests/Extensions/NSAttributedStringParagraphRangeTests.swift +++ b/AztecTests/Extensions/NSAttributedStringParagraphRangeTests.swift @@ -46,4 +46,54 @@ class NSAttributedStringParagraphRangeTests: XCTestCase { XCTAssertEqual(ranges.first?.rangeExcludingParagraphSeparator, expectedRangeWithoutSeparator) XCTAssertEqual(ranges.first?.rangeIncludingParagraphSeparator, expectedRangeWithSeparator) } + + /// Tests that `paragraphRange(for:)` with a paragraph separator character + /// returns the correct `NSRange`. + /// + /// This test was added due to an iOS 17 crash when calling String.paragraphRange(for: range) + /// on a single paragraph separator character. + /// + func testParagraphRangeWorkWithParagraphSeparator() { + let attributedString = NSAttributedString(string: "\u{2029}") + let range = NSRange(location: 0, length: 1) + let expectedRange = NSRange(location: 0, length: 1) + + let paragraphRange = attributedString.paragraphRange(for: range) + + XCTAssertEqual(paragraphRange, expectedRange) + } + + /// Tests that `paragraphRanges(intersecting:)` with a paragraph separator character + /// returns the correct `[NSRange]`. + /// + /// This test was added due to an iOS 17 crash when calling String.paragraphRange(for: range) + /// on a single paragraph separator character. + /// + func testParagraphRangesWorkWithParagraphSeparator() { + let attributedString = NSAttributedString(string: "\u{2029}") + let range = NSRange(location: 0, length: 1) + let expectedRange = NSRange(location: 0, length: 1) + + let ranges = attributedString.paragraphRanges(intersecting: range, includeParagraphSeparator: true) + + XCTAssertEqual(ranges.first!, expectedRange) + } + + /// Tests that `paragraphRanges(intersecting:)` with a paragraph separator character + /// returns the correct `ParagraphRange`. + /// + /// This test was added due to an iOS 17 crash when calling String.paragraphRange(for: range) + /// on a single paragraph separator character. + /// + func testParagraphRangesWorkWithAndWithoutParagraphSeparator() { + let attributedString = NSAttributedString(string: "\u{2029}") + let range = NSRange(location: 0, length: 1) + let expectedRangeWithoutSeparator = NSRange(location: 0, length: 0) + let expectedRangeWithSeparator = NSRange(location: 0, length: 1) + + let ranges = attributedString.paragraphRanges(intersecting: range) + + XCTAssertEqual(ranges.first!.rangeIncludingParagraphSeparator, expectedRangeWithSeparator) + XCTAssertEqual(ranges.first!.rangeExcludingParagraphSeparator, expectedRangeWithoutSeparator) + } } From 00875730d92e22031aec8ae47f0b24042da64aed Mon Sep 17 00:00:00 2001 From: "Tanner W. Stokes" Date: Tue, 12 Sep 2023 13:10:43 -0400 Subject: [PATCH 3/3] Update changelog. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1067a9628..7cf5d98dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,7 +42,7 @@ _None._ ### Bug Fixes -_None._ +* Worked around a crash that could occur when calling String.paragraphRange(for:) on iOS 17. [#1373] ### Internal Changes