To summarize my problem: when I have many child views with widths equal to the width of their parent, where the parent's width is equal to their parent's width, there is a huge performance hit when the window is horizontally resized.
I am retrieving a large number of comments from an API and decided to create an individual NSView
for each comment and then vertically space them all within an NSScrollView
. Each individual comment grows to the height of the comment's text and matches the width of the container. This works fine when there aren't many loaded comments, but when the comments routinely exceed 100, there is a huge performance hit when the window is horizontally resized.
I create each comment's view:
var lastComment:NSView = documentView // The last view to vertically position around
for (index, comment) in commentsArray.enumerate() {
var data = comment
data["attributedString"] = attributedString
let commentView = NSCommentView(data: data)
documentView.addSubview(commentView)
let verticalSpacing = (index == 0) ? 0 : 10 // Position the first comment without any top spacing
let secondAttribute = (index == 0) ? NSLayoutAttribute.Top : NSLayoutAttribute.Bottom
let widthConstraint = NSLayoutConstraint(item: commentView, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: documentView, attribute: NSLayoutAttribute.Width, multiplier: 1, constant: 0)
let topConstraint = NSLayoutConstraint(item: commentView, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: lastComment, attribute: secondAttribute, multiplier: 1, constant: verticalSpacing)
documentView.addConstraints([widthConstraint, topConstraint])
lastComment = commentView
if index == commentsArray.count - 1{
let bottom = NSLayoutConstraint(item: commentView, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: documentView, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 0)
documentView.addConstraint(bottom)
}
}
Where NSCommentView
is defined as:
class NSCommentView: NSView {
func setupFrame(){
self.wantsLayer = true
self.translatesAutoresizingMaskIntoConstraints = false
self.layer?.backgroundColor = NSColor.redColor().CGColor
// Set height of comment, fixed for testing
let heightConstraint = NSLayoutConstraint(item: self, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 50)
self.addConstraint(heightConstraint)
}
func setupTextView(attributedString: NSAttributedString){
let textView = NSTextView()
textView.translatesAutoresizingMaskIntoConstraints = false
textView.verticallyResizable = true
textView.textStorage?.setAttributedString(attributedString)
self.addSubview(textView)
let heightConstraint = NSLayoutConstraint(item: textView, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 50)
textView.addConstraint(heightConstraint)
// The performance hit occurs when I set a width equal to the parent width:
let widthConstraint = NSLayoutConstraint(item: textView, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.Width, multiplier: 1, constant: 0)
self.addConstraint(widthConstraint)
}
convenience init(data:[String: AnyObject?]){
self.init()
setupFrame()
if data["isComment"] as! Bool {
let attributedString = data["attributedString"] as! NSAttributedString
setupTextView(attributedString)
}
}
}
As you can see from the code, the issue is when I attempt to set the width of the NSTextView
to the width of the NSCommentView
. If I simply set it as a constant, there is no real performance degradation.
Is my view hierarchy not setup correctly, or am I overlooking something which is causing this performance issue?