如何操作NSDictionary的内容副本而不更改原始

时间:2015-12-07 07:03:41

标签: ios objective-c cocoa pointers pass-by-reference

修改

以下“更简单”的代码按预期工作。请参阅下面的代码,并在评论中解释我的观察结果。

- (void) changeDictValue
{
//If the method just uses the line below, then calling changeDictValue has no impact on self.bcastSeqNumList
NSMutableDictionary *seqListToUpdate = [NSMutableDictionary dictionaryWithDictionary:self.bcastSeqNumList] ;

//But if it instead uses the line below, calling changeDictValue does change self.bcastSeqNumList  
NSMutableDictionary *seqListToUpdate = self.bcastSeqNumList ;

seqListToUpdate[@(lastContSeqType)]=@(0) ;
seqListToUpdate[@(maxRcvdSeqType)]=@(1) ;
seqListToUpdate[@(missingSeqType)]=nil ;

}

因此,我的代码中看起来有一些错误(或者在调用dictionaryWithDictionary :)时如何处理NSSets的一些特殊的Obj-C逻辑导致与missingSeqType键关联的NSSet受到影响,即使我正在对从self.bcastSeqNumList派生的新字典进行操作。有线索吗?

结束编辑

我有NSDictionary代表序列号 1.一个键(lastContSeqType)表示最大的序列号X,这样我就收到了所有序列号< = X 2.一个键(maxRcvdSeqType)表示到目前为止我收到的最大序列号 3.一个键(missingSeqType)表示一组“缺失序列号”

我有一个用于“广播消息”的字典和一个用于远端的每个单播消息的字典。

当我从服务器获得存储的序列号列表时,我使用存储在我的末尾的序列号列表和接收的序列号列表来确定要检索的序列号。

当我执行以下代码行时,

getMissingSequenceNumsFromServer:(NSDictionary *)dict 的第一个实现中,事情按预期工作,bcastSeqNumList正在更新,lastContSeqType更新为4和{ {1}}为空。

在第二个实现中,我从self。missingSeqType的内容创建一个新的字典,然后操纵这个“复制的”字典,我不希望自我。bcastSeqNumList受到影响。方法中的任何操作。我发现bcastSeqNumList密钥不受影响,但lastContSeqType密钥受到影响并变为空列表(即missingSeqType对象@(4)被删除)。为什么会这样?

NSNumber

案例1实施

self.bcastSeqNumList= [@{@(lastContSeqType) : @(1), @(maxRcvdSeqType) : @(6), @(missingSeqType) : [NSMutableSet setWithObject:@(4)]
                                        } mutableCopy];

  NSLog(@"Bcast seq num list = %@",self.bcastSeqNumList) ;

  NSMutableDictionary *rcvdDict= [@{@"currBroadcastSeqNumStart" : @(5), @"currBroadcastSeqNumEnd" : @(6)
                             } mutableCopy];

  [self getMissingSequenceNumsFromServer:rcvdDict] ;

  NSLog(@"Bcast seq num list = %@",self.bcastSeqNumList) ;

案例2实施

以下一行

- (void) getMissingSequenceNumsFromServer:(NSDictionary *) dict
{   
    NSInteger serverStoreSeqStart=[dict[@"currBroadcastSeqNumStart"] integerValue] ;
    NSInteger serverStoreSeqEnd=[dict[@"currBroadcastSeqNumEnd"] integerValue] ;
    NSMutableDictionary *seqListToUpdate = self.bcastSeqNumList ;


    NSInteger mySeq = [seqListToUpdate[@(lastContSeqType)] integerValue] ;


    if(mySeq < serverStoreSeqStart-1)
    {
        //Ask for all stored messages in server
        //[self getMessagesfromStart:serverStoreSeqStart toEnd:serverStoreSeqEnd] ;
        NSLog(@"Getting messages from %ld and to %ld",serverStoreSeqStart,serverStoreSeqEnd) ;

        NSLog(@"Never received seq nums %ld to %ld",mySeq+1,serverStoreSeqStart-1) ;

        NSInteger nextSeqToRemove ;


      for(nextSeqToRemove=mySeq+1;nextSeqToRemove<=serverStoreSeqStart-1;nextSeqToRemove++)
       {

         if([seqListToUpdate objectForKey:@(missingSeqType)])
         {
          if([seqListToUpdate[@(missingSeqType)] containsObject:[NSNumber numberWithInteger:nextSeqToRemove]])
           {
             NSLog(@"SeqNum %ld is in missing seq num list and being removed since we got server seq %ld > than this",(long)nextSeqToRemove,(long)serverStoreSeqStart) ;
            //Remove it
                            [seqListToUpdate[@(missingSeqType)] removeObject:@(nextSeqToRemove)] ;//
                            //If set is empty
                            if([seqListToUpdate[@(missingSeqType)] count] ==0)
                            {
                                //Nothing left in missing seq table. set it to nil and return
                                [seqListToUpdate removeObjectForKey:@(missingSeqType)] ;
                                seqListToUpdate[@(lastContSeqType)]=seqListToUpdate[@(maxRcvdSeqType)] ;
                                NSLog(@"Missing seq num list empty.  Setting last contig to max = %@",seqListToUpdate[@(lastContSeqType)]) ;

                                break ;
                            }
                 }
               }
               else
               {
                   //mising Seq Type has no elements, nothing to remove
                        break ;
               }
             }

             //At the end..if serverSeqToStore >= maxSeq, then lastCOnt=maxSeq and missing seq empty.
             //Else...if missing seq Empty, then

             seqListToUpdate[@(lastContSeqType)] = [NSNumber numberWithInteger:serverStoreSeqStart-1] ;

             if(seqListToUpdate[@(maxRcvdSeqType)] <= seqListToUpdate[@(lastContSeqType)])
             {
                    seqListToUpdate[@(maxRcvdSeqType)] = seqListToUpdate[@(lastContSeqType)] ;
                    //Set to misisng seq num list = nil
             }
             else
             {
                    //remove seqnums

             }
    }
    else if (mySeq < serverStoreSeqEnd)
    {
        //[self getMessagesfromStart:mySeq+1 toEnd:serverStoreSeqEnd] ;
        NSLog(@"Getting messages from %ld and to %ld",mySeq+1,serverStoreSeqEnd) ;
    }
    else if (mySeq > serverStoreSeqEnd)
    {
        NSLog(@"My stored sequence number %ld exceeds the max stored at server %ld",(long)mySeq,(long)serverStoreSeqEnd) ;
    }
}

替换为以下行,以便 seqListToUpdate = self.bcastSeqNumList ; 的任何更改都不会影响seqListToUpdate的内容

self.bcastSeqNumList

1 个答案:

答案 0 :(得分:2)

你必须制作一份深层副本。目前,您只是将引用复制到相同的对象。您还必须复制字典中引用的对象。

要归档和取消归档的easiest way of doing a deep copy is using NSKeyedArchiver

NSDictionary* deepCopy = [NSKeyedUnarchiver unarchiveObjectWithData:
      [NSKeyedArchiver archivedDataWithRootObject:originalDict]];