【问题标题】:iPhone - Crash using addObject on a NSMutableArrayiPhone - 在 NSMutableArray 上使用 addObject 崩溃
【发布时间】:2011-02-03 23:41:56
【问题描述】:

我这里有问题。又或许我真的很累……

我有一堂课:

@interface THECLASS : UIViewController <UITableViewDelegate> {
    NSMutableArray* param;
}

@property(nonatomic, retain) NSMutableArray* param;

在该类中,我有一个方法,当用户单击 tableViewCell 内的 UISwitch 时调用该方法(我将参数构建到此处未显示的 IBAction 方法中):

@synthesize param;

- (void) changedSelectorValue:(NSIndexPath*)indexPath isOn:(BOOL)isOn {
    [self.param addObject:@"eeeee"];
}

这会使应用程序崩溃并显示以下日志:

2011-02-04 01:31:02.548 Learning Project[3895:207] -[__NSArrayI addObject:]: unrecognized selector sent to instance 0x630c960
2011-02-04 01:31:02.549 Learning Project[3895:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayI addObject:]: unrecognized selector sent to instance 0x630c960'
*** Call stack at first throw:
(
    0   CoreFoundation                      0x00fc4be9 __exceptionPreprocess + 185
    1   libobjc.A.dylib                     0x011195c2 objc_exception_throw + 47
    2   CoreFoundation                      0x00fc66fb -[NSObject(NSObject) doesNotRecognizeSelector:] + 187
    3   CoreFoundation                      0x00f36366 ___forwarding___ + 966
    4   CoreFoundation                      0x00f35f22 _CF_forwarding_prep_0 + 50
    5   Learning Project                    0x00019463 -[ChoixJoursDisponibiliteController changedSelectorValue:isOn:] + 644
    6   Learning Project                    0x000190db -[ChoixJoursDisponibiliteController clickChangedSelectorValue:] + 307
    7   UIKit                               0x002f6a6e -[UIApplication sendAction:to:from:forEvent:] + 119
    8   UIKit                               0x003851b5 -[UIControl sendAction:to:forEvent:] + 67
    9   UIKit                               0x00387647 -[UIControl(Internal) _sendActionsForEvents:withEvent:] + 527
    10  UIKit                               0x004c9c6d -[UISwitch _onAnimationDidStop:finished:context:] + 201
    11  UIKit                               0x00327665 -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 294
    12  UIKit                               0x003274f7 -[UIViewAnimationState animationDidStop:finished:] + 77
    13  QuartzCore                          0x01eab6cb _ZL23run_animation_callbacksdPv + 278
    14  QuartzCore                          0x01eab589 _ZN2CAL14timer_callbackEP16__CFRunLoopTimerPv + 157
    15  CoreFoundation                      0x00fa5fe3 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 19
    16  CoreFoundation                      0x00fa7594 __CFRunLoopDoTimer + 1220
    17  CoreFoundation                      0x00f03cc9 __CFRunLoopRun + 1817
    18  CoreFoundation                      0x00f03240 CFRunLoopRunSpecific + 208
    19  CoreFoundation                      0x00f03161 CFRunLoopRunInMode + 97
    20  GraphicsServices                    0x018f9268 GSEventRunModal + 217
    21  GraphicsServices                    0x018f932d GSEventRun + 115
    22  UIKit                               0x0030542e UIApplicationMain + 1160
    23  Learning Project                    0x00002580 main + 102
    24  Learning Project                    0x00002511 start + 53
    25  ???                                 0x00000001 0x0 + 1
)
terminate called after throwing an instance of 'NSException'

param 由调用者视图填充,例如:

NSMutableArray* filledArray = [NSMutableArray arrayWithObjects:@"SOME TEXT", nil] 
nextController.param = filledArray;

NSLog(@"%@", self.param); 就在崩溃之前:

2011-02-04 02:01:17.205 Learning Project[4223:207] (
    "JOURDISPO_MARDI"
)

为什么会崩溃? 数组在那里,填充而不是nil...看起来定义很好... addObject 是一个NSMutableArray 方法...我不明白

我这里没有展示,但是和removeObject有相同的日志。

【问题讨论】:

  • 你是如何初始化param属性的?
  • @Dave DeLong :从调用者视图来看,它是一个填充数组。没关系,没问题。它被填满了,在其他地方,我用它来做一些展示。
  • 它被[NSMutableArray arrayWithObjects:@"SOME TEXT", nil] 填充在外面

标签: iphone crash nsmutablearray add


【解决方案1】:

答案隐藏在“接受”答案的 cmets 中。我从谷歌来到这里,它解决了我的问题,所以......根据@e.James的评论,让它更清楚:

当你实现“NSCopying”协议,并实现 “copyWithZone”,你不能在你的内部可变数组上使用“copy”——这个 不复制数组(相反,它会创建一个非可变副本)。

例如来自我自己的代码:

// Class: MyClass

@property(nonatomic, retain) NSMutableArray* mutArray;

-(id)copyWithZone:(NSZone *)zone
{
    MyClass* other = [[MyClass alloc] init];

//  other.mutArray = [self.mutArray copy]; // WRONG!
    other.mutArray = [self.mutArray mutableCopy]; // CORRECT!

    return other;
}

【讨论】:

    【解决方案2】:

    由于某种原因,您在NSArray 的实例上调用addObject: 方法,如堆栈跟踪所示。也许您的param 对象的合成吸气剂返回NSArray?不要在你的方法中使用 getter:

    - (void) changedSelectorValue:(NSIndexPath*)indexPath isOn:(BOOL)isOn {
        [param addObject:@"eeeee"];
    }
    

    最终,错误是正确的。您正在对不可变对象调用变异方法。奇怪的是,在我的测试中,这不会导致编译器错误或警告:

    NSMutableArray *array = [[NSArray alloc] init];
    

    编辑: 不管你是否相信,不知何故,param ivar 被设置为一个 NSArray 的实例。覆盖设置器:

    - (void)setParam:(NSMutableArray *)p {
        if (param != p) {
            [param release];
            param = [p retain];
        }
    }
    

    然后在该方法上添加一个断点,并检查何时传入 NSArray。

    【讨论】:

      【解决方案3】:

      您的属性定义为retain,并且您说param 是“来自调用方视图的填充数组”。这可能是你的问题。

      例如,如果您执行以下操作:

      NSArray * filledArray = [NSArray arrayWithObjects:..., nil];
      theClassInstance.param = filledArray;
      

      您将保留一个非可变数组。

      编辑:要调试param 的设置,您可以在.m 中执行以下操作:

      @dynamic param;
      - (NSMutableArray*)param { return param; }
      - (void)setParam:(NSMutableArray*)newArray {
          NSLog(@"setting new param from class: %@",
                NSStringFromClass([newArray class]));
          [newArray retain];
          [param release];
          param = newArray;
      }
      

      【讨论】:

      • @e.James : 不,外面是 NSMutableArray 而不是 NSArray。
      • 我认为它必须是[filledMutableArray mutableCopy],否则你会再次得到NSArray。不过,不确定这是否是问题所在。您能否在崩溃前在您的方法中添加NSLog(@"%@", param); 以查看它是什么类型的对象?
      • 其实,刮一下NSLog。很明显,param 在您的代码中以某种方式设置为不可变的NSArray somewhere。为param 属性创建一个自定义设置器,然后在崩溃发生之前记录其行为可能会有所帮助。
      • 我在答案中添加了示例调试代码。使用它,您应该能够确定 param 何时变为不可变
      • 自定义设置器无法解决您的问题。我建议将其作为调试的一种方式。日志输出应该告诉您从哪里获取非可变数组。
      【解决方案4】:

      你的 init 方法是什么样的?它应该看起来像这样......

      - (id)init
      {
          self = [super init];
      
          self.param = [NSMutableArray array];
      
          return self;
      }
      

      【讨论】:

      • 读取 cmets,它由调用者视图填充。这个数组没有问题,它在控制器的其他地方被填充和使用没有问题。甚至调试器也显示了正确的数组。
      • 为了正确处理事情,您应该始终确保[super init]在执行进一步初始化之前不返回nil。我在第一行使用:if ((self = [super init]) == nil) { return nil; }
      • 如上,一定要检查 [super init] 返回 nil。此外,在 iPhone 上(尽管无论如何,真的),最好避免为 ivars 自动释放对象,这只是浪费计算时间。
      【解决方案5】:

      经过很多努力,我找到了解决问题的方法。就我而言,问题是,

      我有一个可变字典和数组

      @property(strong,nonatomic)NSMutableDictionary *dictInfo;
      @property(retain,nonatomic) NSMutableArray *userAccountsList;
      

      我正在像这样将服务器数组列表添加到 userAccountsList 数组中

       self.dictInfo = [jsonObject valueForKey:@"customerAccountList"];
      

      我已经获取了另一个数组并将服务器数组列表添加到该数组中

      array = [self.dictInfo valueForKey:@"banker"];
      

      最后像这样向 userAccountsListArray 添加数组

                      userAccountsList = [NSMutableArray arrayWithArray:array];
      

      在这里向数组添加额外的对象

                      [userAccountsList addObject:@"Other Account"];//I was getting error here.
      
                      [tableViewObj reloadData];
      

      希望它可以帮助某人。如果有帮助,请投票。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-09-06
        • 2014-03-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多