zoukankan      html  css  js  c++  java
  • category和enumeration的用法

    继承是面向 对象程序设计的一个重要特性,但是继承的一些缺点也越来越多被人们意识到。因为继承有时候会破坏类的封装性,使子类可以使用父类的一些非pubic的方 法。另外当继承树大到一定程度的时候相信许多程序员都不愿意看到,因为毕竟程序不仅仅是要让计算机运行的,更重要的一点就是要人能够看懂,否则这样的程序 也只能束之高阁,供人膜拜了。根据研究表明继承的层次维持3层以下是最容易让人理解。

      所以继承有时候并不表现的那么有用,其实在设计模式中,适配器模式就可以解释用继承是多么的糟糕。那么不用继承objective c如何扩展一个类那,那么Apple的工程师就设计了category这个新语法特性。它的功能就是实现类的扩展而完全不用继承。例如我们要给 NSString类增加一个新的功能计算NSString的长度,并且返回值为NSNumber。假如你要用继承实现

    @interface NSNewString:NSString

    -  (NSNumber)lengthAsNumber;

    @end

    @implement

    - (NSNumber *) lengthAsNumber
    {
    unsigned int length = [self length];
    return ([NSNumber numberWithUnsignedInt: length]);
    }

    @end

    现在我开始调用假如用下面的方法得到一个字符串

    NSNewString *str = [NSString stringWithFormat:"test"]然后你就会得到编译器的警告,stringWithFormat返回的是NSString而你要它成为 NSNewString,这种向下转化是极不安全的。所以你写的子类当调用系统API的时候,无法获得你子类的对象结果你的方法就很难用到此处了。

      而下面用category实现就大不一样了。实现如下:首先要给这个category定义一个名字

    @interface NSString (NumberConvenience)
    - (NSNumber *) lengthAsNumber;
    @end

    @implementation NSString (NumberConvenience)
    - (NSNumber *) lengthAsNumber
    {
    unsigned int length = [self length];
    return ([NSNumber numberWithUnsignedInt: length]);
    } // lengthAsNumber
    @end

    这样我就是用系统的API获得的NSString也可以用我这个方法了。下面就说下category使用的时候应该注意的地方。

      category有2点限制首先你不能在里面定义任何实例变量,它只是方法的扩展,否则你就真的要用继承了。其次category里面的方法不能和原来类 中的方法冲突,否则原来类中的方法就无效了。其实cocoa程序设计中同样有方法定义一个类中的方法为失效的。其实cocoa程序设计中代理 (delegate)这个概念和category联系时非常紧密的,delegates在cocoa编程后面的讲解中自然就知道是什么了,这里不在赘述 了。在appkit中一些控件的使用经常是系统定义了一些category但是不实现它,等到用户使用的时候让用户实现。例如tableview控件中的 - (BOOL) tableView: (NSTableView *) tableView shouldSelectRow: (int) row;方法就是这样实现的。

      下面就来介绍下enumeration的用法,enumeration就是java中常用的迭代器。只不过它比迭代器的语法更简洁。例如NSArray实现了NSEnumeration这个协议就可以用下面的语法迭代集合中的元素。

    NSArray *array = [NSArray arrayWithObjects:
    @"One", @"Two", @"Three", @"Four", nil];
    for (NSString *element in array)
    {
            NSLog(@"element: %@", element);
    }
    这里你不必指定集合遍历的终止条件,也不用指定下标。这种实现比迭代器用起来方便多了吧,同样NSArray遍历也可以用NSEnumeration来实现。
    NSArray *array = [NSArray arrayWithObjects:
    @"One", @"Two", @"Three", @"Four", nil];
    NSEnumerator *enumerator = [array reverseObjectEnumerator];
    for (NSString *element in enumerator)
    {
             if ([element isEqualToString:@"Three"])
             {
                    break;
             }
    }

      任何集合想要实现上面的用法,前提是要实现NSFastEnumeteration这个协议。下面我们就拿一个自己定义的集合例子来实现上面的方法。
    #import <Foundation/Foundation.h>
    #import <vector>
     
    @interface MyFastEnumerationSample : NSObject<NSFastEnumeration>
    {
        std::vector<NSInteger> list;
    }
     
    -(id)initWithCapacity:(NSUInteger)numItems;
     
    @end
     
    @implementation MyFastEnumerationSample
     
    // 初始化这个list
    // 生成一些随机数,插入到list中
    // 之后让枚举类返回
    -(id)initWithCapacity:(NSUInteger)numItems
    {
        self = [super init];
        if(self != nil)
        {
            for(NSInteger i = 0; i < numItems; ++i)
            {
                list.push_back(random());
            }
        }
        return self;
    }
     
    // 这个方法就是fastEnumeration协议中的方法,这里你要实现它
    // 实现这个方法,你有两种选择
    // 1) 使用stackbuf,它是基于array的堆栈。如果用到了这个堆栈,那么你就必需处理下一个参数len的大小。
    // 2) 返回你自己的array对象.如果你遍历完了这个array的所有对象,然后就返回0。例如:一个array的链表的实现需要返回每一个array,知道你遍历完所有的array。
    // 无论上面那种实现方法, state->itemsPtr 必须要赋予一个合法的array(非空)。这个例子采用了方案1,使用stackbuf来存储结果。
    -(NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len
    {
        NSUInteger count = 0;
        // 下面是初始化,仅仅只会做一次。
        // 确保你从来没有设置state->state为0,或者利用了其他的方法初始化它。
        // (下面是使用state->extra中的一个值)。
        if(state->state == 0)
        {
            // 我们不会跟踪变化, 因此我们将设置state->mutationsPtr指向state->extra中的一个数值。
            // 因为这些extra的数值并没有在协议里其他额外的地方使用。
            // If your class was mutable, you may choose to use an internal variable that is updated when the class is mutated.假如你定义的类是可变的,你可能选择使用internal的变量,这个变量可以随着你的类大小的改变而改变。
            // state->mutationsPtr 不能为空。
            state->mutationsPtr = &state->extra[0];
        }
        //现在我们提供items,用来跟踪state->state和决定是否我们已经完成了迭代。
        if(state->state < list.size())
        {
            // 这里需要设置state->itemsPtr指向提供的buffer。
            // 如果需要不停的迭代来实现,那么就可能设置
    state->itemsPtr指向一个内部的c数组对象。
            //
    state->itemsPtr不能为空。
            state->itemsPtr = stackbuf;
            // 把我们list中提供的所有的items都填充到这个堆栈数组中。
            // 假如我们提供的items太多,这个buffer也仅仅装得下len多的东西。后面的就会丢弃掉
            while((state->state < list.size()) && (count < len))
            {
                // 这个例子在运行中生成内容。
                // 一个真正的实现仅仅会从内部的容器中copy对象。
                stackbuf[count] = [NSString stringWithFormat:@"Item %i = %i", state->state, list[state->state]];
                state->state++;
                count++;
            }
        }
        else
        {
            // 我们已经包含了所有的items,因此return 0表明已经做完了。
            count = 0;
        }
        return count;
    }
     
    @end
     
    int main (int argc, const char * argv[])
    {
        NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
     
        // 为了演示,创建一个枚举类的实例,并且枚举里面所有的内容。
        srandomdev();
        MyFastEnumerationSample *example = [[MyFastEnumerationSample alloc] initWithCapacity:50];
        for(id item in example)
        {
            NSLog(@"%@", item);
        }
     
        [pool drain];
        return 0;
    }

    好了,这里你的一个fastenumeration就实现了。其实NSNumeration已经实现了NSFastenumeration这个协议。所以假如有一个自己实现的容器,就可以为这个容器定义一个Numeration,它只要继承 NSNumeration,就可以方便的实现 fastenumeration。想想fastNumeration多么方便你就再也不想用什么数组遍历了。


    原文地址:http://blog.csdn.net/mengtnt/article/details/6035964

  • 相关阅读:
    关于Linux启动时挂载rootfs的几种方式【转】
    文件子系统-(rootfs)根文件系统挂载流程03【转】
    linux根文件系统挂载过程【转】
    linux的initrd机制和initramfs机制之根文件挂载流程:代码分析【转】
    ramdisk配置、解压、创建rootfs、启动简单分析【转】
    linux文件系统初始化过程(4)---加载initrd(中)【转】
    Linux内核学习:EXT4 文件系统在 Linux 内核系统中的读写过程【转】
    Flyway数据库版本管理工具的使用
    RabbitMQ消息发送与接收
    RabbitMQ简介以及安装
  • 原文地址:https://www.cnblogs.com/ligun123/p/2150420.html
Copyright © 2011-2022 走看看