Objective-C - 将对象添加到特定索引处的 NSMutableArray

Objective-C - add object to NSMutableArray at specific index

我正在使用 Parse 作为我的后端。 Saving/fetching 对象在与主线程不同的线程中运行,因此如果您对要获取的数据执行任何操作,则必须在后台块中执行,如下所示:

[Card fetchInBackgroundWithBlock:^(PFObject *object, NSError *error) {
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    ...
    //setting up button based on Card's name
    ...
    [buttonArray addObject:button];
}];

这会创建一个新线程,当从 Parse 中获取对象后,块内的代码就会运行。

我正在为附加到解析用户的卡片数组中的每个卡片对象添加一个按钮。当你按下卡片按钮时,你可以看到它的一些信息,也可以选择删除它。我执行了一个 unwind segue,它处理删除已删除卡片的按钮以及将已删除卡片下方的任何按钮向上移动,因此没有间隙。我的问题是,由于按钮是在另一个线程内创建并添加到我的数组中的,所以一些对象设法被乱序获取。所以我的屏幕可能会按 1 2 3 4 的顺序显示按钮,但我的数组包含按钮 [3,2,1,4]。我如何确保数组中的按钮与它们在屏幕上的显示顺序保持一致,这与卡片存储在我的 Parse 数组中的顺序相同?

这是我目前删除按钮的方式,它移动了不正确的按钮:

-(IBAction)prepareForUnwindPaymentCardDeleted:(UIStoryboardSegue *)segue
{
    [buttonArray removeObjectAtIndex:cardNum];
    for( int i = cardNum; i < [buttonArray count]; i++)
    {
        UIButton *button = [buttonArray objectAtIndex:i];
        [button setTag:i];
        [button setFrame:CGRectMake(xCenter-width/2, button.frame.origin.y - 52, width, height )];
    }
    yValue -= 52;
}

yValue 是按钮原点的y 坐标,如果我添加新的card/button,则对应下一个按钮应该放置的y 坐标。因此,当我删除 button/card 时,我会减少 yValue,这样我就不会在当前的最后一个按钮和新按钮之间留下间隙。 cardNum 是一个变量,等于卡片在我的 Parse 数组中的索引,也是按按钮出现顺序排列的按钮的索引。但是,我发现它并不总是 buttonArray 中按钮的索引。

我想要的是让我的 NSMutableArray buttonArray 的索引与按钮在屏幕上出现的顺序相对应,所以如果我删除按钮 3,我必须将按钮 4-n 向上移动以填补空白,然后递减他们的每个标签以对应正确的卡片。

edit - 我的解决方案最终是在 fetchinbackground 调用之前创建按钮并将其添加到我的数组中。这样,一切都按照我预期的顺序添加。我不正确地使用了 insertObjectAtIndex 方法,但是因为我添加到等于计数的索引,所以它没有抛出任何错误。当我更多地了解它们时,我将使用 NSMutableDictionary 来代替,正如 Josh 和 Duncan 所建议的那样。

你试过NSMutableArray中的insertObject:atIndex:方法了吗?您可以使用 indexOfObject: 来获取卡片数组中卡片的相应索引。

更改您的设计,不要为按钮使用数组。您正在尝试绕过已解决的问题。您有一组对象,即按钮,每个对象都需要与另一组对象(卡片)中的一个相关联。这是一个映射,所以使用一个映射集合:一个NSMutableDictionary.

或者,但不太理想,因为它混淆了 MVC 分离,将按钮 属性 添加到您的 Card 类型,并让每张卡片持有一个(理想情况下是弱)指向其关联按钮的指针。

NSArrays 中不能有空位,因此您不能使用 insertObject:atIndex: 将元素插入到数组末尾之后。

我相信你可以用它在末尾添加一个元素:

NSMutableArray *array = [NSMutableArray arrayWithCapcity: 10];
int index = 0;

[array insertObject @"foo" atIndex: index++];

甚至

array[index++] = @"foo";

正如 Josh 所指出的,如果您想从按钮映射到对象,请使用字典。

如果你真的想要一个 "sparse" 数组,那么你可以用 NSNull 对象填充空白,然后使用 replaceObjectAtIndex:withObject:.

像这样:

int count = 10;
NSMutableArray *array = [NSMutableArray arrayWithCapcity: count];
int index = 0;
for (int index = 0; index<count; index++);
   array[index] = [NSNull null];

然后替换对象(例如在索引 7 处):

[array replaceObjectAtIndex: 7 withObject @"foo"];

array[7] = @"foo";

NSNull 对象的存在就是为了这个特定的目的。它们本质上是一个 "the page intentionally left blank" 对象,用于数组等集合。然后你可以使用像

这样的测试代码
if (array[7] == [NSNull null)
  array[7] = @"foo";

...根据数组中的 "empty" 个位置做出决定。 (在这种罕见的情况下,您可以使用 == 来比较对象是否相等,因为只有一个 NSNull 对象。它是一个单例。)