NSDecimalNumberDivision出错:'NSInvalidArgumentException',原因:' - [__ NSCFNumber decimalNumberByDividingBy:]:无法识别的选择器?

时间:2014-12-01 23:40:41

标签: ios ios7 unrecognized-selector nsdecimalnumber

我的代码是

//    NSDecimalNumber *percentSpent = [distributionModel.spent decimalNumberByDividingBy:self.monthlySummaryModel.totalSpent];
//    NSLog(@"percent:%@", percentSpent);
    NSLog(@"spent:%@, totalSpent:%@", distributionModel.spent, self.monthlySummaryModel.totalSpent);

其中

@property (nonatomic, strong) NSDecimalNumber *spent;
@property (nonatomic) NSDecimalNumber *totalSpent;

percentSpent被注释掉

时,控制台日志就是这个
2014-12-01 15:38:20.161 app-ios[15980:60b] spent:27.01, totalSpent:2077.01 
2014-12-01 15:38:20.201 app-ios[15980:60b] spent:2000, totalSpent:2077.01 
2014-12-01 15:38:20.251 app-ios[15980:60b] spent:40, totalSpent:2077.01 
2014-12-01 15:38:20.292 app-ios[15980:60b] spent:10, totalSpent:2077.01 

当我执行计算percentSpent

时出错
2014-12-01 15:35:44.843 app-ios[15963:60b] -[__NSCFNumber decimalNumberByDividingBy:]: unrecognized selector sent to instance 0x17d4f020 
2014-12-01 15:35:44.851 app-ios[15963:60b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFNumber decimalNumberByDividingBy:]: unrecognized selector sent to instance 0x17d4f020' 
*** First throw call stack: 
(0x2eaadf83 0x3925eccf 0x2eab1917 0x2eab0203 0x2e9ff768 0xac64b 0x313fd8f7 0x313a4c27 0x313a447d 0x312cad59 0x30f4862b 0x30f43e3b 0x30f43ccd 0x30f436df 0x30f434ef 0x30f3d21d 0x2ea79255 0x2ea76bf9 0x2ea76f3b 0x2e9e1ebf 0x2e9e1ca3 0x338e7663 0x3132e14d 0xa48cd 0x3976bab7) 
libc++abi.dylib: terminating with uncaught exception of type NSException 
Signal: 6 (signal SIGABRT)

更新

@interface MonthlySummaryModel : NSObject
@property (nonatomic) int year;
@property (nonatomic) int month;
@property (nonatomic) NSDecimalNumber *totalSpent;
@property (nonatomic, strong) NSArray *distributions;

@interface MonthlySummaryDistributionModel : NSObject
@property (nonatomic, strong) NSString *group;
@property (nonatomic, strong) NSDecimalNumber *spent;

- (MonthlySummaryDistributionModel *) initWithJson: (NSDictionary *) json;
@end

这里有什么问题?

1 个答案:

答案 0 :(得分:3)

关于导致可怕的"无法识别的选择器的原因的简短而愉快的论文"碰撞

您已崩溃,因为您已将NSDecimalNumber消息发送到 NSDecimalNumber - 它是NSNumber。您可能认为它是一个NSDecimalNumber,显然您确实认为,正如您的评论所示:

  

但我将spent作为NSDecimalNumber

...但你错了。相信运行时,而不是你的直觉。运行时比你知道的更清楚(显然)这是什么类型的对象!

为什么会这样?你是如何让自己陷入这种境地的?我会解释一下。

Objective-C是多态。这意味着你如何宣告一件事并不重要;重要的是是什么。他们可以是不同的!原因是你可以关闭类型检查(意外),从而为任何变量分配一个完全错误类型的对象。

例如(拿着我的啤酒并观看):

NSString* s;
NSNumber* n = [NSNumber new];
NSArray* arr = @[n];
s = arr[0];

想想我刚刚做了什么。我将一个NSNumber放入一个数组中,再将它拉出来,并将其分配给一个NSString变量!并且编译器没有阻止我!!!!!这是因为从NSArray中取出一些东西会关闭编译器对该东西的类型检查 - 你可以将它分配给任何,因为编译器不知道什么类型的真的是它。

但它仍然在现实生活中具有类型。因此,当程序运行时,以及在此之后向s发送NSString消息时,您将崩溃,因为它不是 NSString,尽管声明。

这是意外地从编译器中隐藏某些类型的一个例子。有时,人们会做更糟糕的事情;他们故意隐藏编译器中的某些类型。例如(再次拿着我的啤酒):

NSString* s;
NSNumber* n = [NSNumber new];
s = (NSString*) n;

哇!那个时候我只是直接向编译器说谎,并告诉它NSNumber是一个NSString !!!!!编辑耸了耸肩说道:"好吧,等等。我猜他知道我不知道的事情。"所以它让我这样做,它让我将NSNumber分配给NSString变量。

但又一次,它仍然是一个NSNumber。因此,当我们尝试将其视为NSString时,我们将在运行时崩溃。

故事的寓意是:不要骗编译器!让 it 尽可能判断事物的类型。