2016-02-03 15 views
8

Ich verstehe, was der Fehler EXC_BAD_ACCESS im Allgemeinen bedeutet, aber ich bin verwirrt darüber, was in meinem Fall passiert.EXC_BAD_ACCESS mit sortUsingComparator

Ich habe eine benutzerdefinierte Klasse, die eine NSComparator Eigenschaft sortWithThisComparator hat. Wenn diese Eigenschaft durch den Benutzer gesetzt ist, wenn ich einen Artikel in der Instanz der Klasse Eigenschafts-Array items einfügen verwende ich den Komparator die Einfügeort zu bestimmen:

- (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]; 
      } 
     } 
    } 
} 

Alles funktioniert gut, wenn ich nicht setzen einen Komparator, aber wenn ich den Vergleicher verwende bekomme ich einen schlechten Zugriffsfehler:

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; 
     } 
    }]; 

ich einen schlechten Zugang Thread in der zweiten Zeile des Komparator, der einfach ist einer der Parameter über den NSComparator bestanden anzumelden. Aber die Klasseninstanzen, die ich an die insertItem übergebe, sind woanders ohne dieses Problem zugänglich, so dass ich weiß, dass sie ordnungsgemäß instanziiert wurden und ansonsten ordnungsgemäß übergeben werden, da ich sie ohne einen Komparator in die items Eigenschaft einfügen kann. Was fehlt mir hier?


Weitere Details. Ich bin Speichern der NSComparator als

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

Wie speichern Sie den Block als eine Eigenschaft? Kannst du es zur Frage hinzufügen, auch Setzerimplementierung falls vorhanden. – Alistra

+0

@ Alistra Ich habe keinen expliziten Setter geschrieben, sondern setze diese Eigenschaftseigenschaft (strong, atomic) NSComparator sortWithThisComparator; – sunny

Antwort

1

Eigentlich habe ich nur einige Annahmen nach den Codes machen Sie oben erwähnt.

Für den ersten Block, ich denke, self.items ist ein veränderbares Array. Auch in der Funktion insertItem:, sobald sortWithThisComparator nicht gleich Null ist, wird ein neues Objekt eingefügt, nachdem ein Sortierprozess einen Index erhalten hat.

Da Sie einen schlechten Zugang zu Thread-Problemen bekommen, habe ich darauf geachtet, dass Sie in Ihren Codes nicht auf das Threading geachtet haben.

Hier sind einige Vorschläge:

  • NSMutableArray ist nicht Thread-sicher: Ich denke, Sie self.items Betrieb in einem asynchronen Thread stellen. Wenn ich recht habe, erinnern Sie sich daran, jedes Mal, wenn Sie Self.items bearbeiten möchten, NSLock , um es zu schützen.

Ex:

- (void)addItem:(id)item { 
    dispatch_async(self.queue, ^{ 
     [threadLock lock]; 
     [self.items addObject:item]; 
     [threadLock unlock]; 
    } 
} 
  • Eine weitere ist die Sortierung auf änderbaren Array basiert: Ich denke, es zu gefährlich ist, da änderbaren Array nicht sicher ist, fädeln.

Werfen wir einen Blick von dieser Linie nehmen:

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

Meiner Meinung nach, würde ich zum ersten Mal ein Array Kopie tun und Optionen mit NSBinarySearchingInsertionIndex:

NSArray *array = [self.items copy]; 
NSInteger newItemIndex = [array indexOfObject:item inSortedRange:NSMakeRange(0, [array count]) options:NSBinarySearchingInsertionIndex usingComparator:sortWithThisComparator]; 
  • Außerdem habe ich eine Situation gefunden, die self.items.zählen könnte Zero und Sie machen eine NSMakeRange(0, self.items.count). Wahrscheinlich revidieren auch die Bedingung wenig in Funktion insertItem:,
if (!sortWithThisComparator || self.items.count == 0) {}

sind einige Gedanken, die ich bei dieser Bewegung haben. Ich werde mehr hinzufügen, sobald ich Ideen für andere Möglichkeiten bekomme.

+0

Hallo, falls wir zufällig den sortWithComparator der veränderbaren Collections verwenden: Über GCD in einer Hintergrund-Warteschlange, glaubst du, dass eine Sperre noch benötigt wird? – valeCocoa

+0

@valeCocoa Ja, das denke ich in den meisten Fällen. Es sei denn, Sie haben eine dedizierte serielle Dispatch-Warteschlange oder andere Mechanismen für die Steuerung des gemeinsamen Zugriffs eingerichtet. – Allen

0

Was ich vermute, Problem ist mit sortWithThisComparator verwenden, die Sie als Variable nicht als eine Eigenschaft verwenden. Versuchen Sie sortWithThisComparator durch self.sortWithThisComparator zu ersetzen Lassen Sie mich wissen, wenn es hilft