Swift macOS NSTableView очень медленно - PullRequest
2 голосов
/ 09 апреля 2019

Я работаю в Swift (macOS) и имею NSTableView, содержимое которого привязано к NSArrayController. Ячейки tableView могут устанавливать / редактировать данные, используя комбинацию Strings и NSPopUpButtons по девяти столбцам ячейки, которые управляются с помощью привязок с использованием простого подкласса NSObject (то есть со свойствами @objc dynamic var). Кажется, что все привязки работают, и данные верны, но я замечаю, что они становятся невероятно медленными, так как содержимое таблицы становится даже несколько большим (то есть пару сотен элементов).

Кроме того, перевод приложения в фоновый режим и переход на передний план вызывает зависание вращающегося колеса, длина которого коррелирует с количеством элементов в tableView.

У кого-нибудь есть какие-нибудь советы, с чего бы я начал пытаться отследить проблему? Медлительность кажется началась, когда я добавил NSPopUpButtons к некоторым столбцам ячеек, но у меня нет четкого представления о том, почему это так. Привязки NSPopUpButton были созданы в Интерфейсном Разработчике, используя Value Selection -> Selected Value (в Инспекторе Привязок).

ОБНОВЛЕНИЕ: удаление привязок не имеет значения. Из того, что я могу сказать, время тратится на обновление кнопок NSPopUpButtons. Это и удивительно, и неудачно, поскольку они действительно лучший элемент пользовательского интерфейса для того, что я делаю.

61.00 ms   81.3%    0 s                         -[NSTableCellView _windowChangedKeyState]
61.00 ms   81.3%    0 s                          -[NSView _windowChangedKeyState]
59.00 ms   78.6%    0 s                           -[NSPopUpButton _windowChangedKeyState]
59.00 ms   78.6%    0 s                            -[NSControl _windowChangedKeyState]
56.00 ms   74.6%    0 s                             +[NSAppearance _performWithCurrentAppearance:usingBlock:]
55.00 ms   73.3%    0 s                              __35-[NSControl _windowChangedKeyState]_block_invoke
24.00 ms   32.0%    0 s                               -[NSButton updateCell:]
22.00 ms   29.3%    0 s                               -[NSPopUpButtonCell _updateSubviewsInView:includeTitleTextField:]
21.00 ms   28.0%    0 s                                -[NSButtonCell _updateSubviewsInView:includeTitleTextField:]
18.00 ms   24.0%    0 s                                 -[NSButtonCell _updateBackgroundViewWithFrame:inView:]
10.00 ms   13.3%    0 s                                  -[NSButtonCell _bezelRectForBounds:inView:]
7.00 ms    9.3% 0 s                                  _NSSetObjectValueAndNotify
1.00 ms    1.3% 1.00 ms                                  DYLD-STUB$$objc_setProperty_atomic_copy
3.00 ms    4.0% 0 s                                 -[NSView setNeedsDisplay:]
1.00 ms    1.3% 0 s                                -[NSButtonCell _wantsSeparatedContentSubviewsInView:]
9.00 ms   12.0% 0 s                               -[NSButtonCell _windowChangedKeyStateInView:]

Другая вещь, которая делает это трудным, заключается в том, что при выходе из фона появляется пауза до того, как Instruments регистрирует любую активность в приложении. Это может быть просто из-за того, что инструменты перестают фокусироваться ... не уверен, но это не помогает. Приведенный выше пример взят из начальной активности, когда приложение становится активным, но это не отражает всю продолжительность задержки, значительная часть которой вообще не показывает активности в Инструментах.

Если это действительно тот случай, когда использование NSPopUpButtons в столбцах ячеек tableView - плохая идея, тогда мне придется изменить свой дизайн, но если у кого-то есть какие-либо дополнительные предложения, я буду признателен за любой совет.

ОБНОВЛЕНИЕ 2: Взяв большую выборку из паузы, на самом деле есть хороший кусок времени, проведенного в другом месте (боюсь, я не знаю достаточно о просмотре рисунка, чтобы точно понять, что здесь происходит):

302.00 ms   99.0%   0 s      Main Thread  0x20adcd
302.00 ms   99.0%   0 s       start
302.00 ms   99.0%   0 s        main
302.00 ms   99.0%   0 s         NSApplicationMain
302.00 ms   99.0%   0 s          -[NSApplication run]
243.00 ms   79.6%   0 s           -[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:]
243.00 ms   79.6%   0 s            _DPSNextEvent
243.00 ms   79.6%   0 s             _BlockUntilNextEventMatchingListInModeWithFilter
243.00 ms   79.6%   0 s              ReceiveNextEventCommon
243.00 ms   79.6%   0 s               RunCurrentEventLoopInMode
243.00 ms   79.6%   0 s                CFRunLoopRunSpecific
243.00 ms   79.6%   0 s                 __CFRunLoopRun
243.00 ms   79.6%   0 s                  __CFRunLoopDoObservers
243.00 ms   79.6%   0 s                   __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__
243.00 ms   79.6%   0 s                    __65+[CATransaction(NSCATransaction) NS_setFlushesWithDisplayRefresh]_block_invoke
243.00 ms   79.6%   0 s                     CA::Transaction::commit()
206.00 ms   67.5%   0 s                      CA::Context::commit_transaction(CA::Transaction*)
203.00 ms   66.5%   0 s                       CA::Layer::display_if_needed(CA::Transaction*)
102.00 ms   33.4%   0 s                        -[_NSViewBackingLayer display]
97.00 ms   31.8%    0 s                         _NSViewUpdateLayer
92.00 ms   30.1%    0 s                          -[NSButtonBezelView updateLayer]
91.00 ms   29.8%    0 s                           -[NSWidgetView updateLayer]
90.00 ms   29.5%    0 s                            _withOverlaidDictionary
90.00 ms   29.5%    0 s                             __27-[NSWidgetView updateLayer]_block_invoke
90.00 ms   29.5%    0 s                              -[NSAppearance _createOrUpdateLayer:options:]
90.00 ms   29.5%    0 s                               -[NSCompositeAppearance _callCoreUIWithBlock:options:]
88.00 ms   28.8%    0 s                                CUICreateOrUpdateLayer
88.00 ms   28.8%    0 s                                 CUIRenderer::CreateOrUpdateLayer(__CFDictionary const*, CALayer**)
85.00 ms   27.8%    0 s                                  CUICoreThemeRenderer::CreateOrUpdateLayer(CUIDescriptor const*, CALayer**)
81.00 ms   26.5%    0 s                                   CUICoreThemeRenderer::CreateOrUpdateLayerSimple(CUIRenditionKey*, CUIDescriptor const*, CALayer**)
74.00 ms   24.2%    0 s                                    -[CUIThemeFacet updateLayer:effects:]
71.00 ms   23.2%    0 s                                     -[CUIShapeEffectStack newFlattenedImageFromShapeCGImage:withScale:cache:]
37.00 ms   12.1%    0 s                                      -[CIContext createCGImage:fromRect:format:colorSpace:deferred:]

ЗАКЛЮЧИТЕЛЬНОЕ ОБНОВЛЕНИЕ: Да, похоже, проблема в NSPopUpButton. Очень плохо. Я переместил всплывающие окна из tableView и вместо этого использую их для обновления столбцов (просто textFields) в выбранной ячейке tableView. Проблемы со скоростью исчезли.

...