新浪微博 有道云笔记 麦库 EverNote Pocket Instapaper 更多

iOS开发中表视图搜索栏实现中的Objective-C 递归问题

     在学习iphone开发教程的中第8章(也就是《iOS5开发基础教程》最新版的“08 - Sections2”下载地址:http://vdisk.weibo.com/s/hBHg6

要为一个tableView实现搜索功能的时候,遇到了一个问题,学习了好长时间终于想通,现在将问题以及我的理解总结一下.

《iOS5开发基础教程》


书上讲要实现一个MutableDeepCopy协议,关于这个整个思路,协议,需要一个新的副本这些我都能明白,就是里头的具体实现方法遇到点问题,里头的实现代码如下,

NSDictionary-MutableDeepCopy.h

#import <Foundation/Foundation.h>
@interface NSDictionary(MutableDeepCopy)
-(NSMutableDictionary *)mutableDeepCopy;
@end

NSDictionary-MutableDeepCopy.m

#import "NSDictionary-MutableDeepCopy.h"

@implementation NSDictionary(MutableDeepCopy)
- (NSMutableDictionary *)mutableDeepCopy {
    NSMutableDictionary *returnDict = [[NSMutableDictionary alloc]
                                       initWithCapacity:[self count]];
    NSArray *keys = [self allKeys];
    for (id key in keys) {
        id oneValue = [self valueForKey:key];
        id oneCopy = nil;
        
        if ([oneValue respondsToSelector:@selector(mutableDeepCopy)])
            oneCopy = [oneValue mutableDeepCopy];
        else if ([oneValue respondsToSelector:@selector(mutableCopy)])
            oneCopy = [oneValue mutableCopy];
        if (oneCopy == nil)
            oneCopy = [oneValue copy];
        [returnDict setValue:oneCopy forKey:key];
    }
    return returnDict;
}


@end


书上的解释是,

在for里头迭代每个数组,

首先尝试创建深层可变副本(mutableDeepCopy),如果不行,再尝试创建可变副本(mutableCopy),再不行再创建常规副本(copy),
这样保证每个对象都创建了副本。
我的问题是,如果对象a尝试mutableDeepCopy失败,接着去创建可变副本甚至常规副本,
那么这个副本还是深层可变副本吗,不是的话,他怎么能保证a的副本被删除或者改变的时候不会影响到a自己的内容呢?



首先,书本中的例子给了我们三种情况,

 if ([oneValue respondsToSelector:@selector(mutableDeepCopy)])
        oneCopy = [oneValue mutableDeepCopy];
 else if ([oneValue respondsToSelector:@selector(mutableCopy)])
        oneCopy = [oneValue mutableCopy];
if (oneCopy == nil)
        oneCopy = [oneValue copy];
可是我们却只会用到其中一种,大可将其余两种多余的删除掉,

因为书本复制的对象是一个plist文件,并且严格遵守一个键对应一个数组,并且数组中均为字符串,所以我们也可以这样写.m文件

//        if ([oneValue respondsToSelector:@selector(mutableDeepCopy)])//本实例数组中没有字典类型所以不需要对字典进行遍历
//           oneCopy = [oneValue mutableDeepCopy];
//        else if ([oneValue respondsToSelector:@selector(mutableCopy)])
        if ([oneValue respondsToSelector:@selector(mutableCopy)]) 
        oneCopy = [oneValue mutableCopy];
//        if (oneCopy == nil)//数组均不为空,所以不需要考虑这种情况
//            oneCopy = [oneValue copy];

那什么时候才会用到其余两种情况呢?

当数组为空(nil)时会用到

//        if (oneCopy == nil)//数组均不为空,所以不需要考虑这种情况
//            oneCopy = [oneValue copy];

当字典的值--数组中还有字典的时候会用到

//        if ([oneValue respondsToSelector:@selector(mutableDeepCopy)])//本实例数组中没有字典类型所以不需要对字典进行遍历
//            oneCopy = [oneValue mutableDeepCopy];

这个方法是针对字典的而设立的,并且只有字典才能响应这个方法。为什么呢?

NSString 和NSArray 要由mutableCopy进行处理。为什么呢?

下面对这两个问题做一下解答:

观察一下.m文件的开头,

@implementation NSDictionary(MutableDeepCopy)
- (NSMutableDictionary *)mutableDeepCopy ;
于是就知道,这不是一般的方法,在NSDictionary 后面加了一个“()”,这是什么意思?这是一种全新的方法,叫分类方法。就是将NSDictionary 额外地添加了一种函数,即扩展出了一种功能,所说的就是这个mutableDeepCopy函数,所以mutableDeepCopy方法是隶属于NSDictionary类的,是 NSDictionary的分类方法,所以是针对 NSDictionary类型数据进行的深拷贝。(关于分类方法可以参考:
点击打开链接


这是一个递归方法,可能不好理解,为什么我们自定义了一个函数,在自己定义的函数中还要去调用自己呢?而这就叫递归。

为了理解什么叫做递归,我们做一个比喻,我们将需要深复制的字典比作一个压缩包,深复制方法就好像解压缩软件,字典中的值相当于压缩包中的文件,但压缩包中的文件,也可能出现这种情况:压缩包中的文件还是压缩包。也就是说:已经把压缩包用解压缩软件解压了,可是为了解压“缩压缩包中的压缩包”,我们还是得用刚用到的解压缩软件,就好像我们为了深复制字典中出现的字典,甚至字典中的字典的字典,还得用同一个方法:mutableDeepCopy。而这,就叫递归!



那为什么说只需要下面的一种方法就足够了呢?

    if ([oneValue respondsToSelector:@selector(mutableCopy)]) 
        oneCopy = [oneValue mutableCopy];
首先,你要了解Foundation类,NSArray  NSMutableArray NSMutableDictionary NSDctionary NSString都是Foundation类。而Foundation类已经遵守了<NSCopying>和 <NSMutableCopying>协议,即实现了copy和mutableCopy方法,因此Foundation对象可以使用这些方法创建对象的副本或可变副本。(更多Foundation类信息,可参照点击打开链接


如果你要复制的对象是一个plist文件,并且严格遵守一个键对应一个数组,并且数组中均为字符串,就像这本书中的例子一样,我们也可以这样写.m文件

#import "NSDictionary-MutableDeepCopy.h"

@implementation NSDictionary(MutableDeepCopy)
- (NSMutableDictionary *)mutableDeepCopy {
    NSMutableDictionary *returnDict = [NSMutableDictionary dictionaryWithCapacity:[self count]];
    NSArray *keys = [self allKeys];
    for (id key in keys) {
        id oneValue = [self valueForKey:key];
        id oneCopy = nil;
        
//        if ([oneValue respondsToSelector:@selector(mutableDeepCopy)])   //本实例数组中没有字典类型所以不需要对字典进行遍历
//            oneCopy = [oneValue mutableDeepCopy];
//        else if ([oneValue respondsToSelector:@selector(mutableCopy)])
        if ([oneValue respondsToSelector:@selector(mutableCopy)]) 
        oneCopy = [oneValue mutableCopy];    
//        if (oneCopy == nil)      //数组均不为空,所以不需要考虑这种情况
//            oneCopy = [oneValue copy];
        [returnDict setValue:oneCopy forKey:key];
    }
    return returnDict;
}

而这一种mutableCopy方法如何确保

       a的副本被删除或者改变的时候不会影响到a自己的内容呢?

答:NSString NSArray 经mutableCopy方法复制后就变成了可变副本。

如果想深入理解,这就涉及到深拷贝和浅拷贝的问题,这个问题我在上篇文章中已经进行了详细论述,请点击打开链接:iOS开发中表视图搜索栏实现中的Objective-C 深浅拷贝问题





posted @ 2012-11-09 09:44  iTeaTime(技术清谈)  阅读(308)  评论(0编辑  收藏  举报