【问题标题】:How to replace an object in an NSMutableArray at a given index with a new object如何用新对象替换给定索引处的 NSMutableArray 中的对象
【发布时间】:2011-03-05 02:17:10
【问题描述】:

我有一个 NSMutableArray 对象(保留,全部合成),它启动得很好,我可以使用 addObject: 方法轻松地向它添加对象。但是,如果我想用NSMutableArray 中的新对象替换某个索引处的对象,那就不行了。

例如:

ClassA.h:

@interface ClassA : NSObject {
    NSMutableArray *list;
}

@property (nonatomic, copy, readwrite) NSMutableArray *list;

@end

ClassA.m:

#import "ClassA.h"

@implementation ClassA

@synthesize list;

- (id)init 
{
    [super init];
    NSMutableArray *localList = [[NSMutableArray alloc] init];
    self.list = localList;
    [localList release];
    //Add initial data
    [list addObject:@"Hello "];
    [list addObject:@"World"];
}


// Custom set accessor to ensure the new list is mutable
- (void)setList:(NSMutableArray *)newList 
{
    if (list != newList) 
    {
        [list release];
        list = [newList mutableCopy];
    }
}

-(void)updateTitle:(NSString *)newTitle:(NSString *)theIndex
{
    int i = [theIndex intValue]-1;
    [self.list replaceObjectAtIndex:i withObject:newTitle];
    NSLog((NSString *)[self.list objectAtIndex:i]);  // gives the correct output
}

但是,更改仅在方法内部保持正确。从任何其他方法,

NSLog((NSString *)[self.list objectAtIndex:i]);

给出相同的旧值。

我如何才能在特定索引处将旧对象替换为新对象,以便在任何其他方法中也可以注意到更改。

我什至像这样修改了方法,但结果是一样的:

-(void)updateTitle:(NSString *)newTitle:(NSString *)theIndex
{
    int i = [theIndex intValue]-1;

    NSMutableArray *localList = [[NSMutableArray alloc] init];
    localList = [localList mutableCopy];
    for(int j = 0; j < [list count]; j++)
    {
        if(j == i)
        {
            [localList addObject:newTitle];
            NSLog(@"j == 1");
            NSLog([NSString stringWithFormat:@"%d", j]);
        }
        else
        {
            [localList addObject:(NSString *)[self.list objectAtIndex:j]];
        }
    }
    [self.list release];
    //self.list = [localList mutableCopy];
    [self setList:localList];
    [localList release];
}

请大家帮忙:)

【问题讨论】:

  • 抱歉,您确实需要阅读 Objective-C 文档、内存管理论文(非常棒)和属性章节。这段代码真的到处都是错误的......

标签: ios objective-c nsarray


【解决方案1】:

这就是诀窍:

[myMutableArray replaceObjectAtIndex:index withObject:newObject];

【讨论】:

  • 你能告诉我吗。关于replaceObjectAtIndex 方法。如果我调用list[i] = newTitle; 编译没有错误或警告。这种用法有什么问题吗?谢谢:)
  • @Mario 你甚至没有读过这个问题,是吗?但是,嘿,其他 52 个人也没有……
【解决方案2】:

好的,这里有一些混乱。

您无需使用新创建的NSMutableArray 中的mutableCopy 来使其可变。它已经是可变的——线索就在名称中。如果您希望属性具有 copy 语义(您已经设置,当然可能有充分的理由),您只需要在 setter 中执行此操作。但是您当然不需要按照更新后的updateTitle 代码中所示的那样做,这样做会泄漏localList

此外,您将通过self.list 的属性访问和在同一方法中直接使用list 混合在一起。这不是无效的,但这是不好的做法,因为这意味着访问器方法所做的任何其他事情都会被随机绕过。像这样的属性通常通过访问器本身中的self exceptdealloc 以及可能在init 中执行所有操作(对此的意见似乎有所不同),你会直接访问 ivar。

另外,永远不要调用[self.list release]——属性访问器不会给它的调用者所有权。这样做会以泪水告终,请记住我的话。

这些都不能回答真正的问题,这就是为什么您的更改会消失。据我所知,原始的updateTitle 代码并没有解释这一点——它应该可以工作。所以我怀疑你在其他地方打电话 self.list = theOriginalList 并因此撤消你的更改。

更新:

只是为了争论,我将发布我认为您发布的代码可能意味着的样子。我保留了您使用字符串将索引传递给updateTitle,但我想指出这样做是错误。这是一个数字,你应该这样传递它。即使号码来自文本字段或其他内容,这也是呼叫者的关注点;类接口应该指定一个数字。同样,从基于 1 的索引到基于 0 的索引的明显变化。请不要含蓄地做这种事情,这是哭泣和咬牙切齿的秘诀。

ClassA.h:

#import <Cocoa/Cocoa.h>
@interface ClassA : NSObject
{
    NSMutableArray* list;
}
- (void) setList:(NSMutableArray*)newList;
- (void) updateTitle:(NSString*)newTitle forIndex:(NSString*)theIndex;
@property (nonatomic, copy, readwrite) NSMutableArray* list;
@end

ClassA.m:

#import "ClassA.h"

@implementation ClassA
@synthesize list;

- (id) init
{
    if ( self = [super init] )
    {
        list = [[NSMutableArray alloc] init];
        [list addObject:@"Hello "];
        [list addObject:@"World"];
    }
    return self;
}

- (void) setList:(NSMutableArray*) newList
{
    if ( list != newList )
    {
        [list release];
        list = [newList mutableCopy];
    }
}

- (void) updateTitle:(NSString*)newTitle forIndex:(NSString*)theIndex
{
    int i = [theIndex intValue] - 1;
    [self.list replaceObjectAtIndex:i withObject:newTitle];
}

- (void) dealloc
{
    [list release];
    [super dealloc];
}

@end

这清除了各种问题,但请注意updateTitle 基本相同。如果您将所有这些都放入并且更改仍然无法保留,那么您肯定会在某个地方重置list

【讨论】:

  • 感谢walkytalky的建议。我已经相应地修改了我的代码。现在,我浏览了我的代码,在任何地方都找不到一个 self.list = theOriginalList 调用。但我想知道当使用 'replaceObjectAtIndex' 时是否调用了 'setList:' 方法。有任何想法吗?再次感谢:)
  • replaceObjectAtIndex 绝对不应该调用setList——它是数组本身的一个方法,它既不知道也不关心它恰好属于的对象的属性访问器。
  • 你能告诉我吗。关于replaceObjectAtIndex 方法。如果我调用list[i] = newTitle; 编译没有错误或警告。这种用法有什么问题吗?谢谢:)
  • @hqt 用法很好,只是在编写此答案时它还不存在——我认为 Cocoa 数组和字典的相关 ObjC 语法是在 2012 年左右添加的。跨度>
【解决方案3】:

更直接的答案是:

self.list[i] = newTitle;

这就像

[self.list replaceObjectAtIndex:i withObject:newTitle];

【讨论】:

  • 您没有注意到属性中的“副本”会导致每个变体行为不端。
【解决方案4】:

看这一行:

@property (nonatomic, copy, readwrite) NSMutableArray *list;

copy 意味着每当您访问 self.list 时,您不会获得对象的“_list”实例变量,而是该列表的副本。如果你写 [self.list replaceObjectAtIndex... ] 你替换你的列表副本中的一个对象;原始 _list 未更改。只需使用

@property (nonatomic, strong, readwrite) NSMutableArray *list;

为了避免混淆,删除“list”实例变量和@synthesize 语句,然后使用_list 访问实例变量。

【讨论】:

  • 如果我没记错的话,“复制”属性意味着只有在“设置”时实例才会创建副本。但它不会像你提到的那样发生在“get”上。见developer.apple.com/library/ios/documentation/Cocoa/Conceptual/…
  • @OdedRegev 正确,文档中所说的 copy 属性仅适用于新创建的属性。据我了解,Getter 将返回原始对象,但不允许您在所有者的类中修改它(它只会保留在原始的 -unmodified- 属性中)。
【解决方案5】:

对于 Swift 你可以试试:

 //if you have indexPath
   self.readArray.removeAtIndex((indexPath?.row)!)
   self.readArray.insert(tempDict, atIndex: (indexPath?.row)!)
 //tempDict is NSDictionary object.

【讨论】:

    【解决方案6】:

    终于得到了一些完美的代码,

    let DuplicateArray: NSArray = array
    let DuplicateMutableArray: NSMutableArray = []
    DuplicateMutableArray.addObjectsFromArray(DuplicateArray as [AnyObject])
    var dic = (DuplicateMutableArray[0] as! [NSObject : AnyObject])
    dic["is_married"] = "false"
    DuplicateMutableArray[self.SelectedIndexPath] = dic
    array = []
    array = (DuplicateMutableArray.copy() as? NSArray)!
    

    //输出会是这样的

    array =  [
      {
        "name": "Kavin",
        "Age": 25,
        "is_married": "false"
      },
      {
        "name": "Kumar",
        "Age": 25,
        "is_married": "false"
      }
    ]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-12-08
      • 2011-07-05
      • 2011-09-19
      • 1970-01-01
      • 2012-07-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多