2017-05-16 2 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をまったく知らない」という婉曲表現でした。その場合、警告は非常に役立たない:( –

関連する問題