NSNumberFormatter (또는 아마도 다른 NSFormatter)를 NSPopover에서 사용할 수있는 방법이 있습니까?NSPopover에서 NSNumberFormatter 사용
popover의 NSTextField 값은 NSViewController의 representObject에 바인딩됩니다. 잘못된 숫자가 필드에 입력되면 (예 : "asdf") 값이 유효하지 않다는 것을 알리는 시트가 NSWindow에 표시됩니다. NSWindow에는 popover를 표시 한 NSView가 포함되어 있습니다.
는 는는 즉시 확인, 다음 역 추적 가져 오기를 클릭로 : objc_msgSend의 충돌시
* thread #1: tid = 0x4e666a, 0x00007fff931f9097 libobjc.A.dylib`objc_msgSend + 23, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
frame #0: 0x00007fff931f9097 libobjc.A.dylib`objc_msgSend + 23
frame #1: 0x00007fff8a1fa6c8 AppKit`-[NSTextView(NSSharing) becomeKeyWindow] + 106
frame #2: 0x00007fff8a080941 AppKit`-[NSWindow(NSWindow_Theme) acquireKeyAppearance] + 207
frame #3: 0x00007fff8a0800df AppKit`-[NSWindow becomeKeyWindow] + 1420
frame #4: 0x00007fff8a07f5c6 AppKit`-[NSWindow _changeKeyAndMainLimitedOK:] + 803
frame #5: 0x00007fff8a1a205d AppKit`-[NSWindow _orderOutAndCalcKeyWithCounter:stillVisible:docWindow:] + 1156
frame #6: 0x00007fff8a0876c5 AppKit`-[NSWindow _reallyDoOrderWindow:relativeTo:findKey:forCounter:force:isModal:] + 3123
frame #7: 0x00007fff8a0867f0 AppKit`-[NSWindow _doOrderWindow:relativeTo:findKey:forCounter:force:isModal:] + 786
frame #8: 0x00007fff8a086470 AppKit`-[NSWindow orderWindow:relativeTo:] + 162
frame #9: 0x00007fff8a1a1425 AppKit`__18-[NSWindow _close]_block_invoke + 443
frame #10: 0x00007fff8a1a1230 AppKit`-[NSWindow _close] + 370
frame #11: 0x00007fff8a2d0565 AppKit`__106-[NSApplication(NSErrorPresentation) presentError:modalForWindow:delegate:didPresentSelector:contextInfo:]_block_invoke3221 + 50
frame #12: 0x00007fff8a2d02f7 AppKit`-[NSApplication(NSErrorPresentation) _something:wasPresentedWithResult:soContinue:] + 18
frame #13: 0x00007fff8a28fe9d AppKit`-[NSAlert didEndAlert:returnCode:contextInfo:] + 90
frame #14: 0x00007fff8a28f8c2 AppKit`-[NSWindow endSheet:returnCode:] + 368
frame #15: 0x00007fff8a28f49d AppKit`-[NSAlert buttonPressed:] + 107
frame #16: 0x00007fff8a1543d0 AppKit`-[NSApplication sendAction:to:from:] + 327
frame #17: 0x00007fff8a15424e AppKit`-[NSControl sendAction:to:] + 86
frame #18: 0x00007fff8a1a0d7d AppKit`-[NSCell _sendActionFrom:] + 128
frame #19: 0x00007fff8a1ba715 AppKit`-[NSCell trackMouse:inRect:ofView:untilMouseUp:] + 2316
frame #20: 0x00007fff8a1b9ae7 AppKit`-[NSButtonCell trackMouse:inRect:ofView:untilMouseUp:] + 487
frame #21: 0x00007fff8a1b91fd AppKit`-[NSControl mouseDown:] + 706
frame #22: 0x00007fff8a13ad08 AppKit`-[NSWindow sendEvent:] + 11296
frame #23: 0x00007fff8a0d9744 AppKit`-[NSApplication sendEvent:] + 2021
frame #24: 0x00007fff89f29a29 AppKit`-[NSApplication run] + 646
frame #25: 0x00007fff89f14803 AppKit`NSApplicationMain + 940
레지스터이다 : 나는 추측하고있어
(lldb) reg read
General Purpose Registers:
rax = 0x0000610000190740
rbx = 0x0000610000190740
rcx = 0x0000000000000080
rdx = 0x00007fff8a97fd93 "currentEditor"
rdi = 0x0000610000190740
rsi = 0x00007fff8a9612bf "respondsToSelector:"
rbp = 0x00007fff5fbfeae0
rsp = 0x00007fff5fbfeab8
r8 = 0x000000000000002e
r9 = 0xffff9fffffeb1bbf
r10 = 0x00007fff8a9612bf "respondsToSelector:"
r11 = 0xbaddbe5c3e96bead
r12 = 0x0000610000053830
r13 = 0x00007fff931f9080 libobjc.A.dylib`objc_msgSend
r14 = 0x000060000012a500
r15 = 0x00007fff931f9080 libobjc.A.dylib`objc_msgSend
rip = 0x00007fff931f9097 libobjc.A.dylib`objc_msgSend + 23
rflags = 0x0000000000010246
cs = 0x000000000000002b
fs = 0x0000000000000000
gs = 0x00000000c0100000
그것은 때문이다 시트가 표시된 후에 일시적 popover의 창이 사라지고 현재 편집기와 선택기에 응답 할 수있는 객체도 표시됩니다.
Popover 동작을 NSPopoverBehaviorSemitransient로 설정하면 다소 도움이되지만 텍스트 필드에서 잘못된 값으로 Popover가 해제되면 예외가 여전히 발생합니다.
이 시점에서 나는이 문제를 피하기 위해 숫자 값의 수동 검증을 생각할 수 있습니다. 왝.
업데이트 1
브라이언 웹스터는이 AppKit의에 근본적인 문제가 아래의 발견으로.
유효성 검사 요구 사항이 매우 간단했기 때문에 (단지 양의 정수) 해결 방법은 NSPopover에 의해 표시된 NSViewController의 representObject로 사용되는 KVC 개체에서 수동 유효성 검사를 수행하는 것이 었습니다. NSTextField 이 실제로에서 문자열 값을 사용하려고하므로 -valueForKey : 및 -setValue : forKey :는 스칼라 값을 변환하는 데 사용됩니다. 텍스트 필드의 바운드 값에 대해 "즉시 확인"을 설정하면 텍스트 필드가 변경 될 때마다 유효성 검사 메서드가 호출됩니다.
(NSValueTransformer는 유효성 검사 프로세스와 관련이 없으므로이 작업을 수행 할 수 없습니다. 필드가 채워지거나 변경 사항이 저장 될 때만 호출됩니다. 사용자 일부 잘못된 데이터를 입력했다 - NSFormatter 할 것 같은)
가 여기에 내가 무슨 짓을했는지의 요점은 다음과 같습니다.
- (id)valueForKey:(NSString *)key
{
if ([key isEqualToString:@"property1"]) {
return [NSString stringWithFormat:@"%zd", _property1];
}
else if ([key isEqualToString:@"property2"]) {
return [NSString stringWithFormat:@"%zd", _property2];
}
else {
return [super valueForKey:key];
}
}
- (BOOL)validateValue:(inout id *)ioValue forKey:(NSString *)inKey error:(out NSError **)outError
{
if (! *ioValue) {
*ioValue = @"0";
}
else if ([*ioValue isKindOfClass:[NSString class]]) {
NSString *inputString = [[(NSString *)*ioValue copy] autorelease];
inputString = [inputString stringByReplacingOccurrencesOfString:@"," withString:@""];
NSInteger integerValue = [inputString integerValue];
if (integerValue < 0) {
integerValue = -integerValue;
}
*ioValue = [NSString stringWithFormat:@"%zd", integerValue];
}
return YES;
}
- (void)setValue:(id)value forKey:(NSString *)key
{
if ([value isKindOfClass:[NSString class]]) {
if ([key isEqualToString:@"property1"]) {
_property1 = [value integerValue];
}
else if ([key isEqualToString:@"property2"]) {
_property2 = [value integerValue];
}
else {
[super setValue:value forKey:key];
}
}
else {
[super setValue:value forKey:key];
}
}
지금 나는 샤워를해야합니다. 그들은 PaintCode 응용 프로그램에서 작업을 수행하는 방법에 대한 @PixelCutCompany에서 유용한 힌트 몇 가지에
업데이트 2
감사합니다 :
https://twitter.com/PixelCutCompany/status/441695942774104064 https://twitter.com/PixelCutCompany/status/441696198140125184
나는이 함께했다 :
@interface PopupNumberFormatter : NSNumberFormatter
@end
@implementation PopupNumberFormatter
- (BOOL)getObjectValue:(out id *)anObject forString:(NSString *)aString range:(inout NSRange *)rangep error:(out NSError **)error
{
NSNumber *minimum = [self minimum];
NSNumber *maximum = [self maximum];
if (aString == nil || [aString length] == 0) {
if (minimum) {
*anObject = minimum;
}
else if (maximum) {
*anObject = maximum;
}
else {
*anObject = [NSNumber numberWithInteger:0];
}
}
else {
if (! [super getObjectValue:anObject forString:aString range:rangep error:nil]) {
// if the superclass can't parse the string, assign a reasonable default
if (minimum) {
*anObject = minimum;
}
else if (maximum) {
*anObject = maximum;
}
else {
*anObject = [NSNumber numberWithInteger:0];
}
}
else {
// clamp the parsed value to a minimum and maximum (if set)
if (minimum && [*anObject compare:minimum] == NSOrderedAscending) {
*anObject = minimum;
}
else if (maximum && [*anObject compare:maximum] == NSOrderedDescending) {
*anObject = maximum;
}
}
}
return YES;
}
@end
기본적으로 항상 유효한 값을 제공함으로써 시트 또는 대화 상자의 문제점을 피할 수 있습니다.위 코드는 기본값을 지정할 때 최소값과 최대 값을 고려합니다. 서브 클래스는 클램핑 값뿐만 아니라 nil 또는 빈 문자열을 고려합니다.
이렇게하면 기분이 훨씬 덜럽습니다.
오, 그래, 분명히 이것을 AppKit 버그로 분류 할 것입니다. 기회가되면 레이더에서 샘플 프로젝트를 제출할 것입니다. –
버그 보고서를 OpenRadar에 올려 놓고 그 번호를 알려주십시오 : 저는 이것을 확실히 버리고 싶습니다. (그리고 샘플 프로젝트를 만들 시간을내어 주셔서 감사합니다!) – chockenberry