2016-02-03 7 views
8

私はエラーEXC_BAD_ACCESSが一般的に意味するものを理解していますが、私の場合は何が起こっているのか困惑しています。EXC_BAD_ACCESS with sortUsingComparator

私はNSComparatorプロパティsortWithThisComparatorを持つカスタムクラスを持っています。そのプロパティがユーザーによって設定されている場合、私はインスタンスのクラスプロパティ配列itemsに項目を挿入するとき、私は挿入位置を決定するためのコンパレータを使用します。私は、コンパレータを設定しないとき

- (void) insertItem:(id<NSCoding, CKArchivingItem>) item { 
    if (arrayObjectClassString && ![item isKindOfClass:NSClassFromString(arrayObjectClassString)]) { 
     [NSException raise:@"YOU MADE A MISTAKE" format:@"you tried to insert a %@ but I can only accept %@", [item class], arrayObjectClassString]; 
    } else { 
     if (!sortWithThisComparator) { 
      [self.items addObject:item]; 
     } else { 
      NSInteger newItemIndex = [self.items indexOfObject:item inSortedRange:NSMakeRange(0, [self.items count]) options:NSBinarySearchingFirstEqual usingComparator:sortWithThisComparator]; 
      if (newItemIndex >= [self.items count]) { 
       [self.items addObject:items]; 
      } else { 
       [self.items insertObject:item atIndex:newItemIndex]; 
      } 
     } 
    } 
} 

すべてが正常に動作し、私は、コンパレータを使用行うとき、私は悪いアクセスエラーが出ます:

typedef NSComparisonResult (^NSComparator)(id obj1, id obj2); 

... 
    [[CKGenericSingletonSubclass sharedManager] setSortWithThisComparator: ^NSComparisonResult(CKGeneralizedItemSubclass *i1, CKGeneralizedItemSubclass *i2) { 
     NSLog(@"we are inside"); 
     NSLog(@"here is the item 1 %@", i1); 
     NSLog(@"we are comparing this float %f to thisf loat %f", i1.gradeSchoolAverage, i2.gradeSchoolAverage); 
     if (i1.gradeSchoolAverage < i2.gradeSchoolAverage) { 
      return NSOrderedAscending; 
     } else if (i1.gradeSchoolAverage == i2.gradeSchoolAverage) { 
      return NSOrderedSame; 
     } else { 
      return NSOrderedDescending; 
     } 
    }]; 

私は単にNSComparatorを経由して渡されたパラメータのいずれかを記録しているコンパレータの2行目、上の悪いアクセススレッドを取得します。しかし、私がinsertItemに渡しているクラスのインスタンスは、この問題がなければどこからでもアクセスできます。したがって、コンパイラなしでitemsのプロパティに挿入できるので、正しくインスタンス化されています。私はここで何が欠けていますか?


詳細。私は実際に、私はあなたが上記のコードに応じていくつかの仮定を行うことができます

@property (strong, atomic) NSComparator sortWithThisComparator; 
+0

どのようにブロックをプロパティとして保存しますか?あなたはそれを質問に追加することができますかもしあればセッターの実装も追加できますか? – Alistra

+0

@Alistra明示的なセッターを作成せず、むしろこのプロパティープロパティーを設定しました。(強い、アトミック)NSComparator sortWithThisComparator; – sunny

答えて

1

としてNSComparatorを格納しています。

最初のブロックについては、self.itemsは可変配列であると思います。また、関数insertItem:では、sortWithThisComparatorがnilでなければ、ソート処理がインデックスを取得した後に新しいオブジェクトが挿入されます。

スレッドの問題で不正なアクセスが発生するため、あなたのコードでスレッドをうまく処理できなかったと思います。

  • NSMutableArrayのは、スレッドセーフではありません:

    はここにいくつか提案されている、私はあなたが非同期スレッドでself.itemsに 操作を置くと思います。私がこれについて正しいのであれば、self.itemsを編集し、NSLock を使ってそれを保護したいときはいつでも覚えておいてください。

例:

- (void)addItem:(id)item { 
    dispatch_async(self.queue, ^{ 
     [threadLock lock]; 
     [self.items addObject:item]; 
     [threadLock unlock]; 
    } 
} 
  • もう一つは可変配列に基づいてソートされています。私は、可変配列は、スレッドセーフではないので、それはあまりにも 危険だと思います。

のは、この行のを見てみましょう:私の意見では

NSInteger newItemIndex = [self.items indexOfObject:item inSortedRange:NSMakeRange(0, [self.items count]) options:NSBinarySearchingFirstEqual usingComparator:sortWithThisComparator]; 

、私は最初の配列のコピーを行うとNSBinarySearchingInsertionIndexでオプションを設定します:

以外にも
NSArray *array = [self.items copy]; 
NSInteger newItemIndex = [array indexOfObject:item inSortedRange:NSMakeRange(0, [array count]) options:NSBinarySearchingInsertionIndex usingComparator:sortWithThisComparator]; 
  • 、I self.itemsという状況を見つけたカウントは ゼロとなり、NSMakeRange(0, self.items.count)となります。 はおそらくも
if (!sortWithThisComparator || self.items.count == 0) {}

、機能 insertItem:に条件を少し修正し、これらは私がこの運動に持っていくつかの考えです。私は他の可能性のためのアイデアを得ると、さらに追加します。

+0

こんにちは、変更可能なコレクション 'sortWithComparator:バックグラウンドキューのGCD経由で、ロックがまだ必要と思われますか? – valeCocoa

+0

@valeCocoaええ、私はほとんどの場合そうだと思います。専用のシリアルディスパッチキュー、または並行性制御のための他のメカニズムをセットアップしない限り。 – Allen

0

私が推測する問題は、プロパティとしてではなく変数として使用しているsortWithThisComparatorを使用することです。 sortWithThisComparatorself.sortWithThisComparatorに置き換えてみてください。役立つかどうか教えてください