我在使用 NSTextview 时遇到问题,它应该使用日志文件的内容不断更新。该应用程序是一个主从 UI,主视图包含一组“备份”对象,而详细视图包含一个 NSTabView,其中一个选项卡包含 NSTextview。
基本上我想要tail -f logfile
将它的输出放入 NSTextview 之类的东西。我没有使用 NSTask 等,而是将 NSTextview 的“属性字符串”绑定到我的“备份”对象的属性(这样我就可以设置字体):
备份.m
- (NSAttributedString *)logContent
{
NSDictionary *attributes = @{NSFontAttributeName:[NSFont fontWithName:@"Monaco" size:12]};
NSString *str = [NSString stringWithContentsOfURL:theLogfile encoding:NSUTF8StringEncoding error:nil];
if (str) {
NSAttributedString *attrstr = [[NSAttributedString alloc] initWithString:str attributes:attributes];
return attrstr;
} else
return nil;
}
然后,我将一个FSEventStream
连接到日志文件,该日志文件在每次日志文件更改时都会通知回调。在回调中,我手动通知侦听器该属性已更改并向下滚动 NSTextview:
备份.m
- (void)_fsEventsCallback:(NSArray *)eventPaths{
if ([eventPaths containsObject:theLogfile.path]){
[self willChangeValueForKey:@"logContent"];
[self didChangeValueForKey:@"logContent"];
[_myAppDel.logTextView scrollRangeToVisible:NSMakeRange([[_myAppDel.logTextView string] length], 0)];
}}
实际删除是通过以下方式完成的NSNotification
:
应用代理.m
- (void)removeBackupObject:(NSNotification *)notification
{
if (notification.object) {
[self.backupsArrayController removeObject:notification.object];
}
}
这很有效,而且我比使用 NSTask 更喜欢代码,但是当我告诉NSArrayController
删除“备份”对象时,应用程序偶尔会崩溃并出现奇怪的错误:
Crashed Thread: 5 Dispatch queue: com.apple.root.low-priority
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Application Specific Information:
*** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSSetM: 0x60000045f1a0> was mutated while being enumerated.'
terminating with uncaught exception of type NSException
abort() called
Application Specific Backtrace 1:
0 CoreFoundation 0x00007fff8aec425c __exceptionPreprocess + 172
1 libobjc.A.dylib 0x00007fff8a7a4e75 objc_exception_throw + 43
2 CoreFoundation 0x00007fff8aec3b64 __NSFastEnumerationMutationHandler + 164
3 Foundation 0x00007fff8d0e3f05 -[NSISEngine chooseOutgoingRowHeadForIncomingRowHead:] + 305
4 Foundation 0x00007fff8d0e1aa8 -[NSISEngine minimizeConstantInObjectiveRowWithHead:] + 114
5 Foundation 0x00007fff8d0e1623 -[NSISEngine optimize] + 147
6 Foundation 0x00007fff8d0e851d -[NSISEngine constraintDidChangeSuchThatMarker:shouldBeReplacedByMarkerPlusDelta:] + 296
7 Foundation 0x00007fff8d0e839e -[NSISEngine tryToChangeConstraintSuchThatMarker:isReplacedByMarkerPlusDelta:undoHandler:] + 420
8 Foundation 0x00007fff8d0d3798 -[NSLayoutConstraint _tryToChangeContainerGeometryWithUndoHandler:] + 462
9 Foundation 0x00007fff8d0d31b3 -[NSLayoutConstraint _setSymbolicConstant:constant:] + 402
10 AppKit 0x00007fff8e2ac4ba -[NSView(NSConstraintBasedLayout) _autoresizingConstraints_frameDidChange] + 247
11 AppKit 0x00007fff8e2ab25f -[NSView setFrameOrigin:] + 901
12 AppKit 0x00007fff8e2b51b6 -[NSView setFrame:] + 259
13 AppKit 0x00007fff8e682c2f -[NSClipView _updateOverhangSubviewsIfNeeded] + 739
14 AppKit 0x00007fff8e2e80a1 -[NSClipView _scrollTo:animateScroll:flashScrollerKnobs:] + 1984
15 AppKit 0x00007fff8e2e76ff -[NSClipView _reflectDocumentViewFrameChange] + 128
16 AppKit 0x00007fff8e2ac0ac -[NSView _postFrameChangeNotification] + 203
17 AppKit 0x00007fff8e2b5852 -[NSView setFrameSize:] + 1586
18 AppKit 0x00007fff8e447bac -[NSTextView(NSPrivate) _setFrameSize:forceScroll:] + 764
19 AppKit 0x00007fff8e3b222f -[NSTextView setConstrainedFrameSize:] + 633
20 AppKit 0x00007fff8e443f70 -[NSLayoutManager(NSPrivate) _resizeTextViewForTextContainer:] + 1025
21 AppKit 0x00007fff8e35133e -[NSLayoutManager(NSPrivate) _recalculateUsageForTextContainerAtIndex:] + 2636
22 AppKit 0x00007fff8e343fb1 _enableTextViewResizing + 211
23 AppKit 0x00007fff8e34a6ef -[NSLayoutManager textStorage:edited:range:changeInLength:invalidatedRange:] + 557
24 AppKit 0x00007fff8e34a4aa -[NSTextStorage _notifyEdited:range:changeInLength:invalidatedRange:] + 149
25 AppKit 0x00007fff8e451a2c -[NSTextStorage processEditing] + 200
26 AppKit 0x00007fff8e44d832 -[NSTextStorage endEditing] + 110
27 Foundation 0x00007fff8d10b434 -[NSMutableAttributedString removeAttribute:range:] + 219
28 AppKit 0x00007fff8e4ca2c1 -[NSTextView setTextColor:] + 156
29 AppKit 0x00007fff8ea19baf -[_NSTextPlugin showValue:inObject:] + 128
30 AppKit 0x00007fff8e314797 -[NSValueBinder _adjustObject:mode:observedController:observedKeyPath:context:editableState:adjustState:] + 846
31 AppKit 0x00007fff8e3143aa -[NSValueBinder _observeValueForKeyPath:ofObject:context:] + 282
32 AppKit 0x00007fff8e314215 -[NSTextValueBinder _observeValueForKeyPath:ofObject:context:] + 43
33 Foundation 0x00007fff8d09af28 NSKeyValueNotifyObserver + 387
34 Foundation 0x00007fff8d0d7ed1 -[NSObject(NSKeyValueObservingPrivate) _notifyObserversForKeyPath:change:] + 1115
35 AppKit 0x00007fff8e306d88 -[NSController _notifyObserversForKeyPath:change:] + 209
36 AppKit 0x00007fff8e4385ff -[NSArrayController didChangeValuesForArrangedKeys:objectKeys:indexKeys:] + 125
37 AppKit 0x00007fff8e62179f -[NSArrayController _removeObjectsAtArrangedObjectIndexes:contentIndexes:objectHandler:] + 724
38 AppKit 0x00007fff8e621d1f -[NSArrayController _removeObjects:objectHandler:] + 502
在我开始调试出了什么问题或实施NSTask
/tail -f
方法之前,我想知道:
这个问题有更优雅的解决方案吗?