NSMutableArray 难度

Posted

技术标签:

【中文标题】NSMutableArray 难度【英文标题】:NSMutableArray Difficulty 【发布时间】:2012-06-26 03:56:02 【问题描述】:

如果您想查看我遇到问题的代码,请点击以下链接: Code

我的问题与我的past question有关。

我的NSMutableArray 确实有问题,我目前正在将iCarousel 用于我的slotMachine 对象(插槽1 和插槽2)。我的应用程序是这样工作的:

来自PhotoViewController,我创建了一个包含缩略图的视图,然后为它的框架分配了按钮。因此,如果按下 1 张图像,它将通过 NSUserDefaults 保存该整数。 然后我会在我的carouselViewController中检索它

我正在考虑调整数组,但我不能。 我也在这里尝试过我的问题: Comparing with NSMutableArray 如果我能像Array 2 那样做就好了,但还是不行。

(附加信息:)

我已经这样做了,有一个 Viewcontroller 包含 UIImageView 和一个按钮,所以当用户点击它时,我的CustomPicker 会弹出。我的CustomPicker 包含用户在相机胶卷上选取的图像。因此,每个按钮都有一个使用NSUserDefaults 发送到我的iCarouselView 的特定值。 carousel1 用于第一个插槽,carousel2 用于第二个插槽。

这是我想做的:我想强制让它停止到用户选择的索引。 (我在我的carouselDidEndScrollingAnimtaion 中这样做)

在我的carouselDidEndScrollingAnimation 方法中,我测试了我的所有条件(单独),它在比较方面效果很好。 然后当我结合条件时,前两个比较或STOP是正确的,但后面两个总是错误的。或者有时会搞混。

我需要滚动用户选择的两个特定索引/整数(我已经这样做了)能够滚动其中的 2 对,但接下来的两个总是错误的,因为我认为索引正在调整。

图片:

图片下面是我的PhotoViewController,其中包含我的游戏的比较阶段SETTINGUIImageVIewUIButton。将根据它的数字放入的图像将被强制显示,并且应该强制显示。

当我的 iCarousel 启动时,它会在下图中停止(与上图不同):

会强制滚动到PhotoViewController中输入的图片

进入:

总结: 就像这样。我从那里有一个settingsView,我将为Slot1Slot2 导入我的图像(多个)。 然后在另一个 View 中,PhotoViewController 就是上图的显示位置。第一列对应于第一个插槽,然后是第二个插槽。如果按下视图(例如Slot 1 中的No. 1,它将加载从PickerSlot 1 挑选的图像的缩略图。

你必须做 4 次(对)----> 这里显示的我通过 NSUserDefaults 通过 button.tag 获取他们的索引,然后发送到iCarouselView

然后当你完成(按下Done 按钮)它会转到iCarouselView 然后,如上图所示。 按下时它会旋转几秒钟,然后当完成但不停留在用户在PhotoView 中选择的位置时,它将强制滚动到该索引。

问题:

有没有办法让我的数组或我的 iCarousel.view 在我删除时不调整它们的索引。仍然以正确的方式保留我的索引。或者是否有其他解决方案,比如调整我的数组,就像调整我的 PhotoViewController 选择的索引一样。因为我认为当我的数组保留它们的索引时,即使删除我也能解决这个问题。但是还是不行。

希望你能理解我的问题。

【问题讨论】:

你能在简单的项目中分享你的代码吗? @SAKrisT,要我发给你吗? 我仍然不明白真正的问题是什么...您应该编辑整个问题并使其简单清晰 我刚读到这个,我不知道你到底在问什么。 对不起,我还是不明白。您可以添加最后一个简单的问题作为总结吗?以 我如何……? 的形式 【参考方案1】:

有没有办法让我的数组或我的 iCarousel.view 在我删除时不调整它们的索引。仍然以正确的方式保留我的索引。或者还有其他解决方案,比如调整我的数组,就像调整我的 PhotoViewController 选择的索引一样。因为我认为当我的数组保留它们的索引时,即使删除我也能解决这个问题。但是还是不行。

您必须修改 iCarousel 管理其索引的方式的唯一方法是修改代码。实际上,如果您查看 iCarousel.m 中的removeViewAtIndex 方法,您会看到索引是通过 NSDictionary 管理的,并且在删除时,字典会重新排列(项目重新排序)。你可以采用这种方法:

- (void)removeViewAtIndex:(NSInteger)index

    NSMutableDictionary *newItemViews = [NSMutableDictionary dictionaryWithCapacity:[itemViews count] - 1];
    for (NSNumber *number in [self indexesForVisibleItems])
    
        NSInteger i = [number integerValue];
        if (i < index)
        
            [newItemViews setObject:[itemViews objectForKey:number] forKey:number];
        
        else if (i > index)
        
            [newItemViews setObject:[itemViews objectForKey:number] forKey:[NSNumber numberWithInteger:i - 1]];
        
    
    self.itemViews = newItemViews;

您可以将相同的逻辑应用于您的阵列,以便轮播和您的阵列保持同步。当然,如果您将索引存储在某处(slot1/slot2/slot2/slot4?),您还应该在删除元素后更新它们的值。

另一方面,我认为您在这里要问的是如何做一些您认为可以解决您遇到的问题的事情,但您并没有真正解释问题是什么。的确,如果我理解正确的话,你所做的是:

    旋转旋转木马;

    当轮播停止时,如果不是偶然在所需项目上,您“强制”它滚动到该项目。

删除某些元素后没有理由不这样做(除非 iCarousel 有一些错误,那么解决方案就是捕捉错误)。唯一的部分是知道您想要移动到哪个索引。

作为建议,我将从简化您的委托 carouselDidEndScrollingAnimation 方法开始。事实上,您的carouselDidEndScrollingAnimation 有一个名为carousel 的参数,我认为这是您在该方法中应该引用的唯一轮播。如果你没有看到它,这就是推理:你的每个轮播都将停止滚动,carouselDidEndScrollingAnimation 将被调用;这样该方法将被调用两次。每次执行该方法时,您都将修改 carousel1 和 carousel2 的状态(通过调用 scrollToItemAtIndex);因此,在每个轮播中,您将调用 scrollToItemAtIndex 两次。

这对我来说听起来不太正确。因此,您应该找到一种方法,在为 carousel1 调用 carouselDidEndScrollingAnimation 时仅滚动 carousel1,在为 carousel2 调用 carouselDidEndScrollingAnimation 时仅滚动 carousel2。

更一般地说,我想提出的另一点是:

    让轮播停止;

    再次滚动,使其到达所需位置;

似乎不是最好的实现,因为用户会看到轮播停止然后重新开始。

我解决这个问题的方法是直接修改 iCarousel 实现,以便它支持您需要的这种特定行为。

具体来说,看一下 iCarousel.m 中的step 方法。这在每一帧被调用以产生轮播动画。现在,在这个方法中有decelerating 分支:

else if (decelerating)

    CGFloat time = fminf(scrollDuration, currentTime - startTime);
    CGFloat acceleration = -startVelocity/scrollDuration;
    CGFloat distance = startVelocity * time + 0.5f * acceleration * powf(time, 2.0f);
    scrollOffset = startOffset + distance;

    [self didScroll];
    if (time == (CGFloat)scrollDuration)
    
        decelerating = NO;
        if ([delegate respondsToSelector:@selector(carouselDidEndDecelerating:)])
        
            [delegate carouselDidEndDecelerating:self];
        
        if (scrollToItemBoundary || (scrollOffset - [self clampedOffset:scrollOffset]) != 0.0f)
        
            if (fabsf(scrollOffset/itemWidth - self.currentItemIndex) < 0.01f)
            
                //call scroll to trigger events for legacy support reasons
                //even though technically we don't need to scroll at all
                [self scrollToItemAtIndex:self.currentItemIndex duration:0.01];
            
            else
            
                [self scrollToItemAtIndex:self.currentItemIndex animated:YES];
            
        
        else
        
            CGFloat difference = (CGFloat)self.currentItemIndex - scrollOffset/itemWidth;
            if (difference > 0.5)
            
                difference = difference - 1.0f;
            
            else if (difference < -0.5)
            
                difference = 1.0 + difference;
            
            toggleTime = currentTime - MAX_TOGGLE_DURATION * fabsf(difference);
            toggle = fmaxf(-1.0f, fminf(1.0f, -difference));
        
    

您会看到,当轮播停止减速时,它会再次滚动。这与您所做的完全相同,因此您可能会找到一种方法来修改此代码并使轮播精确地滚动到您需要的索引。这样一来,旋转木马的旋转就会更加顺畅。

希望这能有所帮助,并为冗长的回复道歉。

【讨论】:

我认为removeViewAtIndex 是正确的。也许我可以只使用那种方法,而不是另一种?我的索引真的有问题 我尝试使用它 [carousel removeViewAtIndex] 如果我可以在我的视图中调用它,那将是我的答案。请帮帮我先生。 您可以毫无疑问地致电removeViewAtIndex,但我怀疑它会有所帮助;它只会使轮播处于不一致的状态并使其崩溃。您需要做的是修复管理索引的方式——您可以尝试遵循与removeViewAtIndex 相同的路径——这就是我的意思。您不能: 1) 存储索引; 2) 删除一个元素; 3)尝试使用存储的索引,例如- 但最后不清楚你在用你的索引做什么,所以我不能说你的问题是什么...... 首先,坦率地说,您的代码有几个问题,all 会产生错误的结果,正如我上面所概述的。你应该一个一个地修复它们,只有在最后你会看到它有效(也许,如果你足够幸运的话)。我认为,你不会找到一个单一/简单的魔法触摸来解决它的整体问题。修改你的设计并尝试找到做事的正确方法(正如我所说,我在回答中给了你我的 2 美分)。 先生,我只能用一个旋转木马让它工作,但是当有两个旋转木马时,它在某些地方出错了。我知道我的情况是错误的,但我已经想了很久了。管理这些索引真的很难。【参考方案2】:

要知道这里的问题是什么有点困难。您是否对图像使用单个 NSMutableArray 并使用 NSUserDefaults 值来获取数组索引处的对象?

我不能 100% 确定正在发生的事情。用户做什么(以及在什么视图中)以及之后触发了什么(呈现哪个视图)。

您是否试图阻止与从前一个视图中选取的图像相同的图像上的“旋转”图像?

根据您上面的图片,这些图片有一个索引。每次都是这样吗?您从数组中提取可能存在问题。

如果你能提供更多信息,我可以提供帮助。

我再次查看了您粘贴的代码,我认为这可能是您的问题

if (twoSlot1 > [(UIImageView*)[self.carousel2 currentItemView] tag])            
                [self.carousel1 scrollToItemAtIndex:(-twoSlot1)-2 duration: 3.5f];
             else 
                [self.carousel1 scrollToItemAtIndex:-twoSlot1 duration: 3.5f];
            

在所有其他类似的代码块上,您都可以在其中调用每个轮播。在上面的代码中,你调用 carousel 1 两次。

if (slot2 > [(UIImageView*)[self.carousel1 currentItemView] tag])
            [self.carousel1 scrollToItemAtIndex:(-slot2)-2 duration: 3.0f];
             else 
            [self.carousel1 scrollToItemAtIndex:-slot2 duration: 3.0f];    
            

            if (twoSlot2 > [(UIImageView*)[self.carousel2 currentItemView] tag])
            [self.carousel2 scrollToItemAtIndex:(-twoSlot2)-2 duration: 3.5f];    
             else 
            [self.carousel2 scrollToItemAtIndex:-twoSlot2 duration: 3.5f];
            

当你应该调用 2 号时,你调用了 self.carousel1。

这是正确的吗?

【讨论】:

我正在使用 2 个 NSMutableArray。是的,我使用 NSUserDefaults 来获取 2 数组中的对象索引。是的,我试图停止旋转,就像从前一个视图中选择的一样。对于您的其他问题,我在上面对其进行了摘要。请看。 嗨。现在似乎有4个插槽。您能否帮助我们所有人并解释问题是什么以及可能发生在哪里?我不确定您在哪里遇到问题。你甚至会得到比较代码吗? carouselDidEndScrolling 出现问题。 我编辑了我的答案。看起来你在第一个 if pair call 时调用 carousel1 而不是 2 是的,你是对的,但我的问题与调整我的轮播索引有关【参考方案3】:

参考您的问题。您需要一个在从数组中删除成员时不更改其成员索引的数组。

我猜你可以使用 NSMutableDictionary。可以说它是一个关联数组,其中的索引是您选择的,当您从中间删除一个成员时,它们保持不变。 您仍然可以使用 0..n 作为您的索引。你仍然可以使用一些你熟悉的 NSArray 中的方法,例如 count。您可以使用枚举器来遍历字典的所有成员。另一方面,你仍然可以使用你的 for 循环,因为你习惯于将它们与数组一起使用。只需准备好 a) objectForKey:i 如果键/索引不存在(例如被删除)可能会返回 nil,并且该计数会重新调整对象的数量,但不会像数组那样返回最高索引 + 1。

【讨论】:

【参考方案4】:

不确定我是否完全理解,但是当您的可变数组中的一个元素被删除时,而不是仅仅删除它,也许将它与另一个“虚拟”占位符对象一起插入?这样,当删除发生时,您的索引根本不会改变

【讨论】:

例如,如果我有一个对象 1、2、3 的 NSMutableArray,则有一个名为 deleteObject:atIndex 和 insertObject:atIndex 的方法,我可以使用它来删除对象 2 并替换为 -1 .所以 -1 是可变数组中的一个占位符,避免了索引被改变。 虚拟占位符是什么意思?它不会崩溃吗?我尝试插入一个NULL。但崩溃 尝试除null之外的任何东西,添加一些假对象。它必须是 (id) 类型。 (除了 null 之外的任何意思)。 好吧,假设我有一个 NSStrings 数组,NSMutableArray *stringsArray = [[NSMutableArray alloc] initWithObjects:@"String1", @"String2", @"String3", nil];现在说我想删除“String2”并用占位符字符串对象替换。我会说 [stringsArray deleteObjectAtIndex:1]; [stringsArray insertObject:@"PlaceHolderString"];现在数组按顺序保存@"String1"、@"PlaceHolderString"、@"String3"。 好的,所以你有这一行:[carousel1 removeItemAtIndex:index animated:YES];在您的 -(void)deleteItems 方法中。所以添加行 [carousel1 insertItem:(A placeholder object) atIndex:index];并为 index2 做同样的事情。【参考方案5】:

我很难理解你的整体问题,但我可以收集到你问题的症结在于:

有没有办法让我的数组或 iCarousel.view 在我删除时不调整它们的索引。

我不知道它是否会解决您更大的问题,但是使用 NSMutableDictionary 来模拟数组应该允许您这样做。您可以简单地使用索引作为字典的键,然后当您删除与索引关联的项目时,不会调整其他索引。例如:

NSMutableDictionary *arrayDict = [[NSMutableDictionary alloc] init];
[arrayDict setValue:foo forKey:[NSNumber numberWithInt:[arrayDict count]]];
[arrayDict setValue:bar forKey:[NSNumber numberWithInt:[arrayDict count]]];
[arrayDict setValue:fooBar forKey:[NSNumber numberWithInt:[arrayDict count]]];

然后您可以使用[arrayDict objectForKey:[NSNumber numberWithInt:index]] 访问索引处的对象。

请注意,使用 NSNumber 作为 setValue:forKey: 的 key 参数会产生警告,但您可以放心地忽略它(或者如果它打扰您,请使用字符串表示)。

【讨论】:

我说的是用字典完全替换数组,而不仅仅是向数组中添加字典。 您可以通过将数组的索引存储为字典的键来模拟数组。我将编辑答案以展示如何完成此操作的示例。 我的代码怎么样?所以你的意思是我要在 nsmutabledictionary 中分配我的数组索引,然后在我删除时调用它? 像对待可变数组一样对待它。无论您在哪里调用removeObjectAtIndex:,您都可以调用removeObjectForKey: 这并没有解决问题,但仍然给你信用。我很想弄明白。

以上是关于NSMutableArray 难度的主要内容,如果未能解决你的问题,请参考以下文章

过滤自定义对象的 NSMutable 数组

将 NSMutable 数组存储到 sqlite 数据库中

自动发布的 NSMutableArray 未填充

NSUserDefaults NSMutable 数组未在会话之间保存

替换 2d 嵌套 NSMutableArray 内的对象

如何将 NSMutable 数组中的数据存储在 Core Data 中?