2017-05-16 27 views
0

Mac OS X 10.11.6 (El Capitan)의 알림 센터에 알림을 보내려고합니다. 이제는 Objective-C 전문가가 아니므로 this 샘플을 기본으로 사용하고 있습니다.Objective-C 및 CoreFoundation : i386에서 "인식 할 수없는 선택기 전송"오류가 발생했습니다.

전체 목록 : 64 비트 바이너리를 컴파일 할 때

// 
// main.m 
// badonkas 
// 
// Created by Yoshiki Vázquez Baeza on 21/07/13. 
// Copyright (c) 2013 Yoshiki Vázquez Baeza. All rights reserved. 
// 
// Based on the source code as written by Norio Nomura for the project 
// usernotification https://github.com/norio-nomura/usernotification 
// gcc -framework Foundation main.m 
// 

#import <Foundation/Foundation.h> 
#import <objc/runtime.h> 

NSString *fakeBundleIdentifier = nil; 

@implementation NSBundle(swizle) 

// Overriding bundleIdentifier works, but overriding NSUserNotificationAlertStyle does not work. 

- (NSString *)__bundleIdentifier{ 
    if (self == [NSBundle mainBundle]) { 
     return fakeBundleIdentifier ? fakeBundleIdentifier : @"com.apple.terminal"; 
    } else { 
     return [self __bundleIdentifier]; 
    } 
} 

@end 

BOOL installNSBundleHook() 
{ 
    Class class = objc_getClass("NSBundle"); 
    if (class) { 
     method_exchangeImplementations(class_getInstanceMethod(class, @selector(bundleIdentifier)), 
             class_getInstanceMethod(class, @selector(__bundleIdentifier))); 
     return YES; 
    } 
    return NO; 
} 


#pragma mark - NotificationCenterDelegate 

@interface NotificationCenterDelegate : NSObject<NSUserNotificationCenterDelegate> 

@property (nonatomic, assign) BOOL keepRunning; 

@end 

@implementation NotificationCenterDelegate 

- (void)userNotificationCenter:(NSUserNotificationCenter *)center didDeliverNotification:(NSUserNotification *)notification 
{ 
    self.keepRunning = NO; 
} 

@end 

int main(int argc, const char * argv[]) 
{ 

    @autoreleasepool { 
     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 
     NSString *message = [defaults stringForKey:@"-message"] ?: @""; 
     NSString *title = [defaults stringForKey:@"-title"] ?: @"Notification"; 
     NSString *subtitle = [defaults stringForKey:@"-subtitle"] ?: @""; 

     if (installNSBundleHook()) { 

      fakeBundleIdentifier = [defaults stringForKey:@"identifier"]; 

      NSUserNotificationCenter *nc = [NSUserNotificationCenter defaultUserNotificationCenter]; 
      NotificationCenterDelegate *ncDelegate = [[NotificationCenterDelegate alloc]init]; 
      ncDelegate.keepRunning = YES; 
      nc.delegate = ncDelegate; 

      NSUserNotification *note = [[NSUserNotification alloc] init]; 
      note.title = title; 
      note.subtitle = subtitle; 
      note.informativeText = message; 

      [nc deliverNotification:note]; 

      while (ncDelegate.keepRunning) { 
       [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 
      } 
     } 

    } 
    return 0; 
} 

지금이 잘 작동합니다. 나는 -m32 또는 -arch i386 플래그와 32 비트 바이너리로 컴파일한다면, 그것은 충돌 :

2017-05-15 22:16:50.886 a.out[68034:2781117] -[NotificationCenterDelegate setKeepRunning:]: unrecognized selector sent to instance 0x7a019ef0 
2017-05-15 22:16:50.886 a.out[68034:2781117] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NotificationCenterDelegate setKeepRunning:]: unrecognized selector sent to instance 0x7a019ef0' 
*** Call stack at first throw: 
(
    0 CoreFoundation      0x9bc9d9b9 __raiseError + 201 
    1 libobjc.A.dylib      0x9e277fd1 objc_exception_throw + 276 
    2 CoreFoundation      0x9bca1463 -[NSObject(NSObject) doesNotRecognizeSelector:] + 275 
    3 CoreFoundation      0x9bb91dec ___forwarding___ + 1020 
    4 CoreFoundation      0x9bb919ce _CF_forwarding_prep_0 + 14 
    5 a.out        0x000608d5 main + 533 
    6 libdyld.dylib      0x90c4c6ad start + 1 
) 
68034: trace trap 

왜이며, 해결 방법이?

(의심 할 여지없이 누군가가 [정당한 이유를 묻습니다] : 폐쇄 소스 32 비트 프로그램과 연결하려면 32 비트가 필요합니다. 그리고 64 비트 버전을 얻을 수 없습니다. 프로그램. 이미 32 비트 dylib를 연결하고이 문제를 다뤄 보았습니다.)

답변

0

32 비트를 빌드 할 때 컴파일러 경고를 검토 했습니까? 나는 그들이 확실히 설명했을 것이라고 확신한다.

32 비트에서 Objective-C는 속성의 자동 합성을 제공하지 않습니다. "손으로"몇 가지 일을해야합니다. 속성에 백업 저장소를위한 인스턴스 변수가 있어야하는 경우 해당 인스턴스 변수를 선언해야합니다. 게다가, 당신은 @interface에서 그렇게해야합니다; @implementation에서 인스턴스 변수 선언은 지원되지 않습니다.

다음으로 속성을 명시 적으로 @synthesize 필요하거나 접근 자 메서드의 구현을 제공해야합니다. @synthesize을 사용하고 인스턴스 변수의 이름을 속성과 동일한 이름 (밑줄이 없음)으로 지정한 경우 사용할 인스턴스 변수를 지정해야합니다. 예 : @synthesize keepRunning = _keepRunning;. 즉, 기본 인스턴스 변수 이름은 일반적인 규칙과 다르며 자동 합성에서는 기본값입니다.

그래서 :

@interface NotificationCenterDelegate : NSObject<NSUserNotificationCenterDelegate> 
{ 
    BOOL _keepRunning; 
} 

@property (nonatomic, assign) BOOL keepRunning; 

@end 

@implementation NotificationCenterDelegate 

@synthesize keepRunning = _keepRunning; 

- (void)userNotificationCenter:(NSUserNotificationCenter *)center didDeliverNotification:(NSUserNotification *)notification 
{ 
    self.keepRunning = NO; 
} 

@end 
+0

덕분에 명확한 설명 및 솔루션에 대한 무리. "Objective-C 전문가가 아닙니다"는 "나는 Objective-C를 전혀 모른다"라는 완곡 어법이었습니다. 이 경우 경고가 도움이되지 않습니다. –