Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: breakline and space bug #78

Merged
merged 1 commit into from
Sep 20, 2024
Merged

Conversation

zhgchgli0718
Copy link
Member

@zhgchgli0718 zhgchgli0718 commented Sep 20, 2024

private extension NSAttributedString.Key {
    static let breaklinePlaceholder: NSAttributedString.Key = .init("breaklinePlaceholder")
    struct BreaklinePlaceholder: OptionSet {
        let rawValue: Int

        static let tagBoundaryPrefix = BreaklinePlaceholder(rawValue: 1)
        static let tagBoundarySuffix = BreaklinePlaceholder(rawValue: 2)
        static let breaklineTag = BreaklinePlaceholder(rawValue: 3)
    }
}

The root cause is that the custom NSAttributedString.Key requires an extension from Hashable. Otherwise, on iOS 18 and above, it will throw the following error:

Obj-C `-hash` invoked on a Swift value of type `(extension in ZMarkupParser):__C.NSAttributedStringKey.(unknown context at $10380bcc0).BreaklinePlaceholder` that is Equatable but not Hashable; this can lead to severe performance problems.

This leads to a subsequent crash:

*** Terminating app due to uncaught exception 'NSRangeException', reason: 'NSMutableRLEArray replaceObjectsInRange:withObject:length:: Out of bounds'
*** First throw call stack:

However, the expected behavior is to record each breakline position and merge them according to the rules.

If we simply extend the struct with BreaklinePlaceholder: OptionSet, Hashable, the system will automatically merge repeated BreaklinePlaceholder, which is not what we want.

Therefore, I changed it to use a class declaration for the placeholder to maintain the original merging logic.

I also adjusted the crash point in mutableAttributedString.enumerateAttribute(.breaklinePlaceholder, in: NSMakeRange(0, totalLength)), implementing a safer approach by first collecting the ranges and then performing the deletions.

For more details, please refer to this PR.

resolved #77 #75

@zhgchgli0718 zhgchgli0718 self-assigned this Sep 20, 2024
@zhgchgli0718 zhgchgli0718 merged commit b031417 into main Sep 20, 2024
1 check passed
@zhgchgli0718 zhgchgli0718 mentioned this pull request Sep 20, 2024
@dabluck
Copy link

dabluck commented Sep 20, 2024

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Crash
3 participants