This is a follow up from my previous question found here
I am using MarkdownTextView to add basic markdown to a UITextView
. The TextView
is a subclass of MarkdownTextView
.
In my previous question when using copy and paste I got the following error
Fatal error: Use of unimplemented initializer 'init()' for class MarkdownTextStorage
Until I added the following initialiser to MarkdownTextStorage
class
public override convenience init() {
self.init(attributes: MarkdownAttributes())
}
public init(attributes: MarkdownAttributes = MarkdownAttributes()) {
self.attributes = attributes
super.init()
commonInit()
if let headerAttributes = attributes.headerAttributes {
addHighlighter(MarkdownHeaderHighlighter(attributes: headerAttributes))
}
addHighlighter(MarkdownLinkHighlighter())
addHighlighter(MarkdownListHighlighter(markerPattern: "[*+-]", attributes: attributes.unorderedListAttributes, itemAttributes: attributes.unorderedListItemAttributes))
addHighlighter(MarkdownListHighlighter(markerPattern: "\\d+[.]", attributes: attributes.orderedListAttributes, itemAttributes: attributes.orderedListItemAttributes))
// From markdown.pl v1.0.1 <http://daringfireball.net/projects/markdown/>
// Code blocks
addPattern("(?:\n\n|\\A)((?:(?:[ ]{4}|\t).*\n+)+)((?=^[ ]{0,4}\\S)|\\Z)", attributes.codeBlockAttributes)
// Block quotes
addPattern("(?:^[ \t]*>[ \t]?.+\n(.+\n)*\n*)+", attributes.blockQuoteAttributes)
// Se-text style headers
// H1
addPattern("^(?:.+)[ \t]*\n=+[ \t]*\n+", attributes.headerAttributes?.h1Attributes)
// H2
addPattern("^(?:.+)[ \t]*\n-+[ \t]*\n+", attributes.headerAttributes?.h2Attributes)
// Emphasis
addPattern("(\\*|_)(?=\\S)(.+?)(?<=\\S)\\1", attributesForTraits(.traitItalic, attributes.emphasisAttributes))
// Strong
addPattern("(\\*\\*|__)(?=\\S)(?:.+?[*_]*)(?<=\\S)\\1", attributesForTraits(.traitBold, attributes.strongAttributes))
// Inline code
addPattern("(`+)(?:.+?)(?<!`)\\1(?!`)", attributes.inlineCodeAttributes)
}
However once I did this then I got the following bug every time time I copy and paste.
It seems every time the user copy and pastes the initialiser is setting the default MarkdownAttributes
before changing to font properties set in the ViewController
. This screenshot is in between the text attributes being set.
This is how I use TextStorage
in my ViewController
to set the text attributes
let fonty = UIFont(name: font, size: fsize)
attributes.defaultAttributes[NSFontAttributeName] = fonty
attributes.orderedListAttributes?[NSFontAttributeName] = fonty
attributes.orderedListItemAttributes?[NSFontAttributeName] = fonty
attributes.unorderedListAttributes?[NSFontAttributeName] = fonty
attributes.unorderedListItemAttributes?[NSFontAttributeName] = fonty
let textStorage = MarkdownTextStorage(attributes: attributes)
Here is the MarkdownAttributes
struct
public struct MarkdownAttributes {
let fonty = UIFont(name: "OpenSans", size: 30)
public var defaultAttributes: TextAttributes = [
NSFontAttributeName: UIFont.preferredFont(forTextStyle: UIFontTextStyle.body)
]
public var strongAttributes: TextAttributes?
public var emphasisAttributes: TextAttributes?
public struct HeaderAttributes {
public var h1Attributes: TextAttributes? = [
NSFontAttributeName: UIFont.preferredFont(forTextStyle: UIFontTextStyle.headline)
]
public var h2Attributes: TextAttributes? = [
NSFontAttributeName: UIFont.preferredFont(forTextStyle: UIFontTextStyle.headline)
]
public var h3Attributes: TextAttributes? = [
NSFontAttributeName: UIFont.preferredFont(forTextStyle: UIFontTextStyle.headline)
]
public var h4Attributes: TextAttributes? = [
NSFontAttributeName: UIFont.preferredFont(forTextStyle: UIFontTextStyle.subheadline)
]
public var h5Attributes: TextAttributes? = [
NSFontAttributeName: UIFont.preferredFont(forTextStyle: UIFontTextStyle.subheadline)
]
public var h6Attributes: TextAttributes? = [
NSFontAttributeName: UIFont.preferredFont(forTextStyle: UIFontTextStyle.subheadline)
]
func attributesForHeaderLevel(_ level: Int) -> TextAttributes? {
switch level {
case 1: return h1Attributes
case 2: return h2Attributes
case 3: return h3Attributes
case 4: return h4Attributes
case 5: return h5Attributes
case 6: return h6Attributes
default: return nil
}
}
public init() {}
}
public var headerAttributes: HeaderAttributes? = HeaderAttributes()
fileprivate static let MonospaceFont: UIFont = {
let bodyFont = UIFont.preferredFont(forTextStyle: UIFontTextStyle.body)
let size = bodyFont.pointSize
return UIFont(name: "Menlo", size: size) ?? UIFont(name: "Courier", size: size) ?? bodyFont
}()
public var codeBlockAttributes: TextAttributes? = [
NSFontAttributeName: MarkdownAttributes.MonospaceFont
]
public var inlineCodeAttributes: TextAttributes? = [
NSFontAttributeName: MarkdownAttributes.MonospaceFont
]
public var blockQuoteAttributes: TextAttributes? = [
NSForegroundColorAttributeName: UIColor.darkGray
]
public var orderedListAttributes: TextAttributes? = [
NSFontAttributeName: fontWithTraits(.traitBold, font: UIFont.preferredFont(forTextStyle: UIFontTextStyle.body))
]
public var orderedListItemAttributes: TextAttributes? = [
NSFontAttributeName: UIFont.preferredFont(forTextStyle: UIFontTextStyle.body),
NSForegroundColorAttributeName: UIColor.darkGray
]
public var unorderedListAttributes: TextAttributes? = [
NSFontAttributeName: fontWithTraits(.traitBold, font: UIFont.preferredFont(forTextStyle: UIFontTextStyle.body))
]
public var unorderedListItemAttributes: TextAttributes? = [
NSFontAttributeName: UIFont.preferredFont(forTextStyle: UIFontTextStyle.body),
NSForegroundColorAttributeName: UIColor.darkGray
]
public init() {
}
}
Does anyone know how I can fix the bug so when the initialiser is called the values are set to the user defined values and not the default ones ?
Add an init function that takes the user's defined values, and call your class or your superclass init() (depends what you want to do..)
You should add just one of the following functions, you don't want to add both of them:
public override init(attributes: MarkdownAttributes = MarkdownAttributes()) {
super.init(attributes)
}
public override convenience init(attributes: MarkdownAttributes = MarkdownAttributes()) {
init(attributes: attributes)
}
To call it, you can now use the code you showed above:
let fonty = UIFont(name: font, size: fsize)
attributes.defaultAttributes[NSFontAttributeName] = fonty
attributes.orderedListAttributes?[NSFontAttributeName] = fonty
attributes.orderedListItemAttributes?[NSFontAttributeName] = fonty
attributes.unorderedListAttributes?[NSFontAttributeName] = fonty
attributes.unorderedListItemAttributes?[NSFontAttributeName] = fonty
let textStorage = MarkdownTextStorage(attributes: attributes)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With