foundation_foundation框架 - CSDN
精华内容
参与话题
  • FOUNDATION的基本介绍

    2016-01-06 22:03:43
    对做iOS的一下日常笔记

    FOUNDATION简介

    foundation 单词的解释就是基础

     乔帮主 离开苹果以后开创了 NeXT -> 一套用来开发的类库

     Foundation 库是基础是关注基本数据类型和基本类的使用的库

     主要学习字符串处理数组处理键值对处理


    11-字符串的常见用法

    字符串操作类有两个: NSString(不可变字符串), NSMutableString(可变字符串)。

    1, 掌握一个规律将常用的方法分类增删改查与其他

    2, 如果有的方法有多种情况我们首先学习最简单的使用熟练后在考虑复杂的

     NSString 是不可变字符串主要讨论 增加  查询与其他

     增加(创建方法)

     1, 字面量         2, 构造方法      3, 快速创建对象方法


    URL 统一资源地址就是网址

    查询类的方法

    1, 比较

          isEqualToString

          compare

    strcmp("1", "2"); // 如果 > 返回 大于0的数如果 == 返回 0; 如果 < 返回小于0的数


    01-字符串检查前后缀方法

    所谓的检查前后缀就是判断字符串是以什么开头或者以什么结尾

    关键字: has

    hasPrefix 判断前缀       hasSuffix 判断后缀的




    终端命令:
    ls 列出当前目录下的所有内容     cd 切换目录   clear  清除终端   touch 是修改文件的属性的命令,如果文件不存在,则创建文件
    open 打开文件  cp 复制文件


    NSRange 用来专门表示范围
     range.location  表示位置  即 起始位置  
    range.length   表示长度, 即 多少个字符


    字符串的查找方法:
     字符串的查找方法是指从一个字符串中找某一个部分的方法 关键字 rangeOf  

    如果没有找到就会返回 location 为一个非常大的数字, length  0

     这个非常大的数字在 OC 中被定义为 NSNotFound


    字符串截取

    字符串截取就是在一个字符串中将符合要求的一部分字符串取出来

     关键字 substring

     科学计算中 表示范围的时候一般左边取得到右边取不到


    字符串的替换

    将一个字符串中的某一个部分替换成需要的样子

       关键字 stringBy + replace


    字符串与基本数据的转换:  字符串提供了一系列的 "类型Value” 方法


    去除首尾空格:去除首尾空格

       关键字 stringBy + trimming


    NSMutableString简介

    对于 可变字符串 使用最多的就是创建字符串和构造字符串

    也就是说追加与插入使用的比较多一般都是使用 NSString


    使用可变的字符串其目的就是为了构造动态的字符串

       因此使用的时候都是首先创建一个 空的字符串作为容器

       然后根据需要构造相应的字符串

    1, 加入字符串           appendString        appendFormat


    NSArray的基本使用

    数组的概念

    1, C 语言的数组不方便存储对象

    2, C 语言数组不是面向对象的缺少强大的方法

    3, C 语言的数组是定长的数组, OC 中提供了可变长度的数组

    NSArray  不可变数组

    NSMutableArray   可变数组


    数组的常用方法    1, count 属性用来活动数组中元素的个数 NSLog(@"%lu", arr.count);


    2, objectAtIndex 方法  

          NSString *s = [arr objectAtIndex:1];

           NSLog(@"%@", s);

    3, 遍历

            // for (int i = 0; i < arr.count; i++) {

            //      NSString *s = [arr objectAtIndex:i];

            //      NSLog(@"%@", s);

            // }

    在数组中还提供了快速获得首尾元素的属性 :arr.firstObject // 最开始的元素

                                    arr.lastObject  // 最后的元素

         数组提供了一个方法, IndexOfObject 表示对象的索引


    数组的遍历:除了可以使用 for 循环来遍历数组外,可以使用for-in循环 block 来进行遍历

    语法:  for (临时变量 in 数组) {

                使用临时变量访问结果

            }

    语法  [arr enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {

    obj 表示当前循环的临时变量 for-in 中的临时变量的含义相同

                 idx 当前下标好比 for 循环中的 i

                 stop 表示是否停止 break 相同



    字符串与数组的连用


    NSMutableArray

    使用可变数组基本上就是为了实现动态的生成数组

            一般就是生成一个空的数组然后的将元素一个个加入进来


    键值对数据的概念与意义

    键值对

     1, 为什么需要这个数据类型数组可以存储数据但是查找比较费劲

     2, 是什么类型

          键值对是一个"散列表(哈希表, hash)". 他的特点就是按照键来存储数据

          系统中在存储数据的时候都是按照键和值一起存储的

          首先根据键算出一个唯一的地址来然后将数据存储到该地址处

        那么很容易根据键九算出地址取出数据因此在查找技术中常常使用该方法

    可变键值对

    一般来讲可变键值对也是创建一个空的作为容器使用

    NSMutableDictionary *dic1 = [[NSMutableDictionary allocinit];

     NSMutableDictionary *dic2 = [NSMutableDictionary dictionary];



    NSFileManager

    该类完成对文件的基本信息的访问与基本操作保存创建删除移动复制

    1, 该类为一个单例类

      创建的时候使用 defaultManager 类方法来获得对象



    常见的结构体 

    NSPoint  CGPoint(ios一般用这个)


    NSNumberNSValue


    NSDate

    NSDateFormatter 是一个格式化日期与字符串的类

        他可以轻松的实现字符串与时间对象的互相转换并且可以格式化任意的输入形式



    集合的内存管理

    1. 对象别集合引用后,所有者就会 +1    2.集合被释放后,会将引用的所有对象都 —1


    copy概念的引入

    系统中 NSObject 提供了 copy 的方法(mutableCopy)

            // 该方法用来复制当前对象创建一个新的副本

            

            // 但是该方法如何创建是未定义的它调用了 copyWithZone: 来具体实现如何创建

            

            // 如果我们需要自己创建副本就需要实现该方法

            

            // 而该方法由 NSCopying 来提供


    深拷贝与浅拷贝 

    第一种观点      1 第一种观点

                1> 浅拷贝是指拷贝引用变量

                 Person *p1 = [Person new];

                 Person *p2 = p1;  // 浅拷贝

            

                 2> 深拷贝就是连同对象数据一起全部拷贝

                  Person *p3 = [Person new];

                    p3.属性 = p1.属性;

    第二种观点       2 第二种观点

             拷贝 就是要 复制

             如果对象中的属性都是值类型那么深拷贝与浅拷贝没有区别

             如果对象属性含有类类型的那么深拷贝与浅拷贝才有区别

    展开全文
  • 分析在IOS开发中一个重要的框架Foundation,主要内容有:(来自转载) Foundation概述常用结构体日期字符串数组字典装箱和拆箱反射拷贝文件操作归档 Foundation概述 为什么前面说的内容中新建一个类的时候我们...

    分析在IOS开发中一个重要的框架Foundation,主要内容有:(来自转载)

    1. Foundation概述
    2. 常用结构体
    3. 日期
    4. 字符串
    5. 数组
    6. 字典
    7. 装箱和拆箱
    8. 反射
    9. 拷贝
    10. 文件操作
    11. 归档

    Foundation概述

    为什么前面说的内容中新建一个类的时候我们都是选择Cocoa Class呢?Cocoa是什么呢?

    Cocoa不是一种编程语言(它可以运行多种编程语言),它也不是一个开发工具(通过命令行我们仍然可以开发Cocoa程序),它是创建Mac OS XIOS程序的原生面向对象API,为这两者应用提供了编程环境。

    我们通常称为“Cocoa框架,事实上Cocoa本身是一个框架的集合,它包含了众多子框架,其中最重要的要数“Foundation”“UIKit”。前者是框架的基础,和界面无关,其中包含了大量常用的API;后者是基础的UI类库,以后我们在IOS开发中会经常用到。这两个框架在系统中的位置如下图:


    其实所有的Mac OS XIOS程序都是由大量的对象构成,而这些对象的根对象都是NSObjectNSObject就处在Foundation框架之中,具体的类结构如下:




    通常我们会将他们分为几类:

    1. 值对象
    2. 集合
    3. 操作系统服务:文件系统、URL、进程通讯
    4. 通知
    5. 归档和序列化
    6. 表达式和条件判断
    7. Objective-C语言服务

    UIKit主要用于界面构架,这里我们不妨也看一下它的类结构:


    常用结构体

    Foundation中定义了很多常用结构体类型来简化我们的日常开发,这些结构体完全采用Objective-C定义,和我们自己定义的结构体没有任何区别,之所以由框架为我们提供完全是为了简化我们的开发。常用的结构体有NSRangeNSPointNSSizeNSRect

    //

    //  main.m

    //  FoundationFramework

    //

    //  Created by Kenshin Cui on 14-2-16.

    //  Copyright (c) 2014 Kenshin Cui. All rights reserved.

    //


    #import <Foundation/Foundation.h>


    /*NSRange表示一个范围*/

    void test1(){

        NSRange rg={3,5};//第一参数是起始位置第二个参数是长度

        //NSRange rg;

        //rg.location=3;

        //rg.length=5;

        //NSRange rg={.location=3,.length=5};

        //常用下面的方式定义 NSRange rg2=NSMakeRange(3,5);//使用NSMakeRange定义一个NSRange 

        //打印NSRange可以使用Foundation中方法 NSLog(@"rg2 is %@", NSStringFromRange(rg2));//注意不能直接NSLog(@"rg2 is %@", rg2),因为rg2不是对象(准确的说%@是指针)而是结构体

    }

    /*NSPoint表示一个点*/

    void test2(){

        NSPoint p=NSMakePoint(10, 15);//NSPoint其实就是CGPoint

        //这种方式比较常见 NSPoint p2=CGPointMake(10, 15);

        NSLog(NSStringFromPoint(p2));

    }

    /*NSSize表示大小*/

    void test3(){

        NSSize s=NSMakeSize(10, 15);//NSSize其实就是CGSize

        //这种方式比较常见 CGSize s2=CGSizeMake(10, 15);

        NSLog(NSStringFromSize(s2));

    }

    /*NSRect表示一个矩形*/

    void test4(){

        NSRect r=NSMakeRect(10, 5, 100, 200);//NSRect其实就是CGRect

        //这种方式比较常见 NSRect r2=CGRectMake(10, 5, 100, 200);

        NSLog(NSStringFromRect(r2));

    }


    int main(int argc, const char * argv[]) {

        @autoreleasepool {

            test1();

            test2();

            test3();

            test4();

        } return 0;

    }

    可以看到对于常用结构体在Foundation框架中都有一个对应的make方法进行创建,这也是我们日后比较常用的操作;而且与之对应的还都有一个NSStringFromXX方法来进行字符串转换,方便我们调试。上面也提到NSSize其实就是CGSizeNSRect其实就是CGRect,我们可以通过查看代码进行确认,例如NSSize定义:


    继续查看CGSize的代码:


    日期

    接下来熟悉一下Foundation框架中日期的操作

    //

    //  main.m

    //  FoundationFramework

    //

    //  Created by Kenshin Cui on 14-2-16.

    //  Copyright (c) 2014 Kenshin Cui. All rights reserved.

    //


    #import <Foundation/Foundation.h>



    int main(int argc, const char * argv[]) {

        

        NSDate *date1=[NSDate date];//获得当前日期

        NSLog(@"%@",date1); //结果:2014-07-16 07:25:28 +0000

        

        NSDate *date2=[NSDate dateWithTimeIntervalSinceNow:100];//在当前日期的基础上加上100秒,注意在ObjC中多数时间单位都是秒

        NSLog(@"%@",date2); //结果:2014-07-16 07:27:08 +0000

        

        NSDate *date3=[NSDate distantFuture];//随机获取一个将来的日期

        NSLog(@"%@",date3); //结果:4001-01-01 00:00:00 +0000

        

        NSTimeInterval time=[date2 timeIntervalSinceDate:date1];//日期之差,返回单位为秒

        NSLog(@"%f",time); //结果:100.008833

        

        NSDate *date5=[date1 earlierDate:date3];//返回比较早的日期

        NSLog(@"%@",date5); //结果:2014-07-16 07:25:28 +0000

        

        //日期格式化

        NSDateFormatter *formater1=[[NSDateFormatter alloc]init];

        formater1.dateFormat=@"yy-MM-dd HH:mm:ss";

        NSString *datestr1=[formater1 stringFromDate:date1];

        NSLog(@"%@",datestr1); //结果:14-07-16 15:25:28

        //字符串转化为日期

        NSDate *date6=[formater1 dateFromString:@"14-02-14 11:07:16"];

        NSLog(@"%@",date6); //结果:2014-02-14 03:07:16 +0000


        return 0;

    }

    字符串

    不可变字符串

    ObjC中字符串操作要比在C语言中简单的多,在下面的例子中你将看到字符串的初始化、大小写转化、后缀前缀判断、字符串比较、字符串截取、字符串转换等,通过下面的例子我们基本可以掌握常用的字符串操作(注意这些内容虽然基本,但却是十分常用的操作,需要牢记)

    //

    //  main.m

    //  FoundationFramework

    //

    //  Created by Kenshin Cui on 14-2-16.

    //  Copyright (c) 2014 Kenshin Cui. All rights reserved.

    //


    #import <Foundation/Foundation.h>



    /**字符串操作*/

    void test1(){

        char *str1="C string";//这是C语言创建的字符串

        NSString *str2=@"OC string";//ObjC字符串需要加@,并且这种方式创建的对象不需要自己释放内存


        //下面的创建方法都应该释放内存

        NSString *str3=[[NSString alloc] init];

        str3=@"OC string";

        NSString *str4=[[NSString alloc] initWithString:@"Objective-C string"];

        NSString *str5=[[NSString alloc] initWithFormat:@"age is %i,name is %.2f",19,1.72f];

        NSString *str6=[[NSString alloc] initWithUTF8String:"C string"];//C语言的字符串转换为ObjC字符串


        //以上方法都有对应静态方法(一般以string开头),不需要管理内存(系统静态方法一般都是自动释放)

        NSString *str7=[NSString stringWithString:@"Objective-C string"];

    }

    void test2(){

        NSLog(@"\"Hello world!\" to upper is %@",[@"Hello world!" uppercaseString]);

        //结果:"Hello world!" to upper is HELLO WORLD!

        NSLog(@"\"Hello world!\" to lowwer is %@",[@"Hello world!" lowercaseString]);

        //结果:"Hello world!" to lowwer is hello world!

         

        //首字母大写,其他字母小写

        NSLog(@"\"Hello world!\" to capitalize is %@",[@"Hello world!" capitalizedString]);

        //结果:"Hello world!" to capitalize is Hello World!

         

        BOOL result= [@"abc" isEqualToString:@"aBc"];

        NSLog(@"%i",result);

        //结果:0

        NSComparisonResult result2= [@"abc" compare:@"aBc"];//如果是[@"abc" caseInsensitiveCompare:@"aBc"]则忽略大小写比较

        if(result2==NSOrderedAscending){

            NSLog(@"left<right.");

        }else if(result2==NSOrderedDescending){

            NSLog(@"left>right.");

        }else if(result2==NSOrderedSame){

            NSLog(@"left=right.");

        }

        //结果:left>right.

    }

    void test3(){

        NSLog(@"has prefix ab? %i",[@"abcdef" hasPrefix:@"ab"]);

        //结果:has prefix ab? 1

        NSLog(@"has suffix ab? %i",[@"abcdef" hasSuffix:@"ef"]);

        //结果:has suffix ab? 1

        NSRange range=[@"abcdefabcdef" rangeOfString:@"cde"];//注意如果遇到cde则不再往后面搜索,如果从后面搜索或其他搜索方式可以设置第二个options参数

        if(range.location==NSNotFound){

            NSLog(@"not found.");

        }else{

            NSLog(@"range is %@",NSStringFromRange(range));

        }

        //结果:range is {2, 3}

    }

    //字符串分割

    void test4(){

        NSLog(@"%@",[@"abcdef" substringFromIndex:3]);//从第三个索引开始(包括第三个索引对应的字符)截取到最后一位

        //结果:def

        NSLog(@"%@",[@"abcdef" substringToIndex:3]);0开始截取到第三个索引(不包括第三个索引对应的字符)

        //结果:abc

        NSLog(@"%@",[@"abcdef" substringWithRange:NSMakeRange(2, 3)]);

        //结果:cde

        NSString *str1=@"12.abcd.3a";

        NSArray *array1=[str1 componentsSeparatedByString:@"."];//字符串分割

        NSLog(@"%@",array1);

         /*结果:

          (

             12,

             abcd,

             3a

          )

          */

     

    }

    //其他操作

    void test5(){

        NSLog(@"%i",[@"12" intValue]);//类型转换

        //结果:12

        NSLog(@"%zi",[@"hello world,世界你好!" length]);//字符串长度注意不是字节数

        //结果:17

        NSLog(@"%c",[@"abc" characterAtIndex:0]);//取出制定位置的字符

        //结果:a

        const char *s=[@"abc" UTF8String];//转换为C语言字符串

        NSLog(@"%s",s);

        //结果:abc

    }


    int main(int argc, const char * argv[]) {

        test1();

        test2();

        test3();

        test4();

        test5();

        return 0;

    }

    注意:上面代码注释中提到的需要释放内存指的是在MRC下的情况,当然本质上在ARC下也需要释放,只是这部分代码编译器会自动创建。

    扩展--文件操作

    ObjC中路径、文件读写等操作是利用字符串来完成的,这里通过几个简单的例子来演示(首先在桌面上新建一个test.txt文件,里面存储的内容是”hello world,世界你好!

    //

    //  main.m

    //  FoundationFramework

    //

    //  Created by Kenshin Cui on 14-2-16.

    //  Copyright (c) 2014 Kenshin Cui. All rights reserved.

    //


    #import <Foundation/Foundation.h>



    void test1(){

        //读取文件内容

        NSString *path=@"/Users/kenshincui/Desktop/test.txt";

        NSString *str1=[NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];

        //注意上面也可以使用gb2312 gbk,例如kCFStringEncodingGB_18030_2000,但是需要用CFStringConvertEncodingToNSStringEncoding转换

        NSLog(@"str1 is %@",str1);

        //结果:str1 is hello world,世界你好!


        

        

        

        //上面我们看到了读取文件,但并没有处理错误,当然在ObjC中可以@try @catch @finnally但通常我们并不那么做

        //由于我们的test.txt中有中文,所以使用下面的编码读取会报错,下面的代码演示了错误获取的过程

        NSError *error;

        NSString *str2=[NSString stringWithContentsOfFile:path encoding:kCFStringEncodingGB_18030_2000 error:&error];//注意这句话中的error变量是**error,就是指针的指针那就是指针的地址,由于error就是一个指针此处也就是error的地址&error,具体原因见下面补充

        if(error){

            NSLog(@"read error ,the error is %@",error);

        }else{

            NSLog(@"read success,the file content is %@",str2);

        }

        //结果:read error ,the error is Error Domain=NSCocoaErrorDomain Code=261 "The file couldn’t be opened using the specified text encoding." UserInfo=0x100109620 {NSFilePath=/Users/kenshincui/Desktop/test.txt, NSStringEncoding=1586}


        

        

        

        //读取文件内容还有一种方式就是利用URl,它除了可以读取本地文件还可以读取网络文件

        //NSURL *url=[NSURL URLWithString:@"file:///Users/kenshincui/Desktop/test.txt"];

        NSURL *url=[NSURL URLWithString:@"http://www.apple.com"];

        NSString *str3=[NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];

        NSLog(@"str3 is %@",str3);

    }

    void test2(){

        //下面是文件写入

        NSString *path1=@"/Users/kenshincui/Desktop/test2.txt";

        NSError *error1;

        NSString *str11=@"hello world,世界你好!";

        [str11 writeToFile:path1 atomically:YES encoding:NSUTF8StringEncoding error:&error1];//automically代表一次性写入,如果写到中间出错了最后就全部不写入

        if(error1){

            NSLog(@"write fail,the error is %@",[error1 localizedDescription]);//调用localizedDescription是只打印关键错误信息

        }else{

            NSLog(@"write success!");

        }

        //结果:write success!

    }

    //路径操作

    void test3(){

        NSMutableArray *marray=[NSMutableArray array];//可变数组

        [marray addObject:@"Users"];

        [marray addObject:@"KenshinCui"];

        [marray addObject:@"Desktop"];


        NSString *path=[NSString pathWithComponents:marray];

        NSLog(@"%@",path);//字符串拼接成路径

        //结果:Users/KenshinCui/Desktop


        NSLog(@"%@",[path pathComponents]);//路径分割成数组

        /*结果: 

         (

            Users,

            KenshinCui,

            Desktop

        )

        */


        NSLog(@"%i",[path isAbsolutePath]);//是否绝对路径(其实就是看字符串是否以“/”开头)

        //结果:0

        NSLog(@"%@",[path lastPathComponent]);//取得最后一个目录

        //结果:Desktop

        NSLog(@"%@",[path stringByDeletingLastPathComponent]);//删除最后一个目录,注意path本身是常量不会被修改,只是返回一个新字符串

        //结果:Users/KenshinCui

        NSLog(@"%@",[path stringByAppendingPathComponent:@"Documents"]);//路径拼接

        //结果:Users/KenshinCui/Desktop/Documents

    }

     //扩展名操作

    void test4(){

        NSString *path=@"Users/KenshinCui/Desktop/test.txt";

        NSLog(@"%@",[path pathExtension]);//取得扩展名,注意ObjC中扩展名不包括"."

        //结果:txt

        NSLog(@"%@",[path stringByDeletingPathExtension]);//删除扩展名,注意包含"."

        //结果:Users/KenshinCui/Desktop/test

        NSLog(@"%@",[@"Users/KenshinCui/Desktop/test" stringByAppendingPathExtension:@"mp3"]);//添加扩展名

        //结果:Users/KenshinCui/Desktop/test.mp3

    }


    int main(int argc, const char * argv[]) {

        test1();

        test2();

        test3();

        test4();

        return 0;

    }

    注意:在上面的例子中我们用到了可变数组,下面会专门介绍。

    可变字符串

    我们知道在字符串操作过程中我们经常希望改变原来的字符串,当然这在C语言中实现比较复杂,但是ObjC为我们提供了新的可变字符串类NSMutableString,它是NSString的子类。

    //

    //  main.m

    //  FoundationFramework

    //

    //  Created by Kenshin Cui on 14-2-16.

    //  Copyright (c) 2014 Kenshin Cui. All rights reserved.

    //


    #import <Foundation/Foundation.h>



    int main(int argc, const char * argv[]) {

        

        /*可变字符串,注意NSMutableStringNSString子类*/

        //注意虽然initWithCapacity分配字符串大小,但是不是绝对的不可以超过此范围,声明此变量对性能有好处

        NSMutableString *str1= [[NSMutableString alloc] initWithCapacity:10];

        [str1 setString:@"hello"];//设置字符串

        NSLog(@"%@",str1);

        //结果:hello


        [str1 appendString:@",world!"];//追加字符串

        NSLog(@"%@",str1);

        //结果:hello,world!


        [str1 appendFormat:@"我的年龄是%idear,I love you.",18];

        NSLog(@"%@",str1);

        //结果:hello,world!我的年龄是18dear,I love you.

        

        //替换字符串

        NSRange range=[str1 rangeOfString:@"dear"];

        [str1 replaceCharactersInRange:range withString:@"Honey"];

        NSLog(@"%@",str1);

        //结果:hello,world!我的年龄是18Honey,I love you.

        

        //插入字符串

        [str1 insertString:@"My name is Kenshin." atIndex:12];

        NSLog(@"%@",str1);

        //结果:hello,world!My name is Kenshin.我的年龄是18Honey,I love you.

        

        //删除指定字符串

        [str1 deleteCharactersInRange:[str1 rangeOfString:@"My name is Kenshin."]];//删除指定范围的字符串

        NSLog(@"%@",str1);

        //结果:hello,world!我的年龄是18Honey,I love you.

        

        return 0;

    }

    数组

    不可变数组

    下面将演示常用的数组操作:初始化、数组对象的方法执行、数组元素的遍历、在原有数组基础上产生新数组、数组排序等

    //

    //  main.m

    //  FoundationFramework

    //

    //  Created by Kenshin Cui on 14-2-16.

    //  Copyright (c) 2014 Kenshin Cui. All rights reserved.

    //


    #import <Foundation/Foundation.h>

    #import "Person.h"



    void test1(){

        //NSArray长度不可变所以初始化的时候就赋值,并且最后以nil结尾

        //此外需要注意NSArray不能存放C语言的基础类型

        NSObject *obj=[[NSObject alloc]init];

        //NSArray *array1=[[NSArray alloc] initWithObjects:@"abc",obj,@"cde",@"opq", nil];

        NSArray *array1=[NSArray arrayWithObjects:@"abc",obj,@"cde",@"opq",@25, nil];

        NSLog(@"%zi",array1.count);//数组长度,结果:5

        NSLog(@"%i",[array1 containsObject:@"cde"]);//是否包含某个对象,结果:1

        NSLog(@"%@",[array1 lastObject]);//最后一个对象,结果:25

        NSLog(@"%zi",[array1 indexOfObject:@"abc"]);//对象所在的位置:0

        

        Person *person1=[Person personWithName:@"Kenshin"];

        Person *person2=[Person personWithName:@"Kaoru"];

        Person *person3=[Person personWithName:@"Rosa"];

        NSArray *array2=[[NSArray alloc]initWithObjects:person1,person2,person3, nil];

        [array2 makeObjectsPerformSelector:@selector(showMessage:) withObject:@"Hello,world!"];//执行所有元素的showMessage方法,后面的参数最多只能有一个

        /*结果:

         My name is Kenshin,the infomation is "Hello,world!".

         My name is Kaoru,the infomation is "Hello,world!".

         My name is Rosa,the infomation is "Hello,world!".

         */

    }

    //数组的遍历

    void test2(){

        NSObject *obj=[[NSObject alloc]init];

        NSArray *array=[[NSArray alloc] initWithObjects:@"abc",obj,@"cde",@"opq",@25, nil];

        //方法1

        for(int i=0,len=array.count;i<len;++i){

            NSLog(@"method1:index %i is %@",i,[array objectAtIndex:i]);

        }

        /*结果:

         method1:index 0 is abc

         method1:index 1 is <NSObject: 0x100106de0>

         method1:index 2 is cde

         method1:index 3 is opq

         method1:index 4 is 25

         */

        

        

        //方法2

        for(id obj in array){

            NSLog(@"method2:index %zi is %@",[array indexOfObject:obj],obj);

        }

        /*结果:

         method2:index 0 is abc

         method2:index 1 is <NSObject: 0x100602f00>

         method2:index 2 is cde

         method2:index 3 is opq

         method2:index 4 is 25

         */

        

        

        //方法3,利用代码块方法

        [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {

            NSLog(@"method3:index %zi is %@",idx,obj);

            if(idx==2){//idx=2时设置*stopYES停止遍历

                *stop=YES;

            }

        }];

        /*结果:

         method3:index 0 is abc

         method3:index 1 is <NSObject: 0x100106de0>

         method3:index 2 is cde

         */

        

        

        //方法4,利用迭代器

        //NSEnumerator *enumerator= [array objectEnumerator];//获得一个迭代器

        NSEnumerator *enumerator=[array reverseObjectEnumerator];//获取一个反向迭代器

        //NSLog(@"all:%@",[enumerator allObjects]);//获取所有迭代对象,注意调用完此方法迭代器就遍历完了,下面的nextObject就没有值了

        id obj2=nil;

        while (obj2=[enumerator nextObject]) {

            NSLog(@"method4:%@",obj2);

        }

        /*结果:

         method4:25

         method4:opq

         method4:cde

         method4:<NSObject: 0x100106de0>

         method4:abc

         */

    }

    //数组派生出新的数组

    void test3(){

        NSArray *array=[NSArray arrayWithObjects:@"1",@"2",@"3", nil];

        NSArray *array2=[array arrayByAddingObject:@"4"];//注意此时array并没有变

        NSLog(@"%@",array2);

        /*结果:

         (

             1,

             2,

             3,

             4

         )

         */

        

        

        NSLog(@"%@",[array2 arrayByAddingObjectsFromArray:[NSArray arrayWithObjects:@"5",@"6", nil]]);//追加形成新的数组

        /*结果:

         (

             1,

             2,

             3,

             4,

             5,

             6

         )

         */

        

        

        NSLog(@"%@",[array2 subarrayWithRange:NSMakeRange(1, 3)]);//根据一定范围取得生成一个新的数组

        /*结果:

         (

             2,

             3,

             4

         )

         */

        

        

        NSLog(@"%@",[array componentsJoinedByString:@","]);//数组连接,形成一个字符串

        //结果:1,2,3

        

        //读写文件

        NSString *path=@"/Users/KenshinCui/Desktop/array.xml";

        [array writeToFile:path atomically:YES];

        NSArray *array3=[NSArray arrayWithContentsOfFile:path];

        NSLog(@"%@",array3);

        /*结果:

         (

             1,

             2,

             3

         )

         */

    }

    //数组排序

    void test4(){

        //方法1,使用自带的比较器

        NSArray *array=[NSArray arrayWithObjects:@"3",@"1",@"2", nil];

        NSArray *array2= [array sortedArrayUsingSelector:@selector(compare:)];

        NSLog(@"%@",array2);

        /*结果:

         (

             1,

             2,

             3

         )

         */

        

        

        //方法2,自己定义比较器

        Person *person1=[Person personWithName:@"Kenshin"];

        Person *person2=[Person personWithName:@"Kaoru"];

        Person *person3=[Person personWithName:@"Rosa"];

        NSArray *array3=[NSArray arrayWithObjects:person1,person2,person3, nil];

        NSArray *array4=[array3 sortedArrayUsingSelector:@selector(comparePerson:)];

        NSLog(@"%@",array4);

        /*结果:

         (

             "name=Kaoru",

             "name=Kenshin",

             "name=Rosa"

         )

         */

        

        

        //方法3使用代码块

        NSArray *array5=[array3 sortedArrayUsingComparator:^NSComparisonResult(Person *obj1, Person *obj2) {

            return [obj2.name compare:obj1.name];//降序

        }];

        NSLog(@"%@",array5);

        /*结果:

         (

             "name=Rosa",

             "name=Kenshin",

             "name=Kaoru"

         )

         */

        

        

        //方法4 通过描述器定义排序规则

        Person *person4=[Person personWithName:@"Jack"];

        Person *person5=[Person personWithName:@"Jerry"];

        Person *person6=[Person personWithName:@"Tom"];

        Person *person7=[Person personWithName:@"Terry"];

        NSArray *array6=[NSArray arrayWithObjects:person4,person5,person6,person7, nil];

        //定义一个排序描述

        NSSortDescriptor *personName=[NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES];

        NSSortDescriptor *accountBalance=[NSSortDescriptor sortDescriptorWithKey:@"account.balance" ascending:YES];

        NSArray *des=[NSArray arrayWithObjects:personName,accountBalance, nil];//先按照personname排序再按照accountbalance排序

        NSArray *array7=[array6 sortedArrayUsingDescriptors:des];

        NSLog(@"%@",array7);

        /*结果:

         (

             "name=Jack",

             "name=Jerry",

             "name=Terry",

             "name=Tom"

         )

         */

    }


    int main(int argc, const char * argv[]) {

        test1();

        test2();

        test3();

        test4();

        return 0;

    }

    需要注意几点:

    • NSArray中只能存放对象,不能存放基本数据类型,通常我们可以通过在基本数据类型前加@进行转换;
    • 数组中的元素后面必须加nil以表示数据结束;
    • makeObjectsPerformSelector执行数组中对象的方法,其参数最多只能有一个;
    • 上面数组操作中无论是数组的追加、删除、截取都没有改变原来的数组,只是产生了新的数组而已;
    • 对象的比较除了使用系统自带的方法,我们可以通过自定义比较器的方法来实现;

    可变数组

    下面看一下可变数组的内容:

    //

    //  main.m

    //  FoundationFramework

    //

    //  Created by Kenshin Cui on 14-2-16.

    //  Copyright (c) 2014 Kenshin Cui. All rights reserved.

    //


    #import <Foundation/Foundation.h>

    #import "Person.h"



    void test1(){

        Person *person1=[Person personWithName:@"Kenshin"];

        Person *person2=[Person personWithName:@"Kaoru"];

        Person *person3=[Person personWithName:@"Rosa"];

        NSMutableArray *array1=[NSMutableArray arrayWithObjects:person1,person2,person3, nil];

        NSLog(@"%@",array1);

        /*结果:

         (

             "name=Kenshin",

             "name=Kaoru",

             "name=Rosa"

         )

         */

        

        Person *person4=[Person personWithName:@"Jack"];//此时person4retainCount1

        [array1 addObject:person4];//添加一个元素,此时person4retainCount2

        NSLog(@"%@",array1);

        /*结果:

         (

             "name=Kenshin",

             "name=Kaoru",

             "name=Rosa",

             "name=Jack"

         )

         */

        

        [array1 removeObject:person3];//删除一个元素

        NSLog(@"%@",array1);

        /*结果:

         (

             "name=Kenshin",

             "name=Kaoru",

             "name=Jack"

         )

         */

        

        [array1 removeLastObject];//删除最后一个元素,//此时person4retainCount1

        NSLog(@"%@",array1);

        /*结果:

         (

             "name=Kenshin",

             "name=Kaoru"

         )

         */

        

        [array1 removeAllObjects];//删除所以元素

        

        //注意当往数组中添加一个元素时会retain因此计数器+1,当从数组中移除一个元素时会release因此计数器-1

        //NSMutalbeArray对象release的时候会依次调用每一个对象的release

    }

    void test2(){

        NSMutableArray *array1=[NSMutableArray arrayWithObjects:@"1",@"3",@"2", nil];

        NSLog(@"%@",array1);

        /*结果:

         (

             1,

             3,

             2

         )

         */

        

        NSArray *array2= [array1 sortedArrayUsingSelector:@selector(compare:)];//注意这个方法没有修改array1

        NSLog(@"%@",array1);

        /*结果:

         (

             1,

             3,

             2

         )

         */

        

        NSLog(@"%@",array2);

        /*结果:

         (

             1,

             2,

             3

         )

         */

        [array1 sortUsingSelector:@selector(compare:)];//这个方法会修改array1

        NSLog(@"%@",array1);

        /*结果:

         (

             1,

             2,

             3

         )

         */

        

    }


    int main(int argc, const char * argv[]) {

        

        test1();

        

        test2();

        

        return 0;

    }

    • 可变数组中的元素后面必须加nil以表示数据结束;
    • 往一个可变数组中添加一个对象,此时这个对象的引用计数器会加1,当这个对象从可变数组中移除其引用计数器减1。同时当整个数组销毁之后会依次调用每个对象的releaes方法。
    • 在不可变数组中无论对数组怎么排序,原来的数组顺序都不会改变,但是在可变数组中如果使用sortUsingSelector:排序原来的数组顺序就发生了变化。

     

    字典

    字典在我们日常开发中也是比较常用的,通过下面的代码我们看一下在ObjC中的字典的常用操作:初始化、遍历、排序

    //

    //  main.m

    //  FoundationFramework

    //

    //  Created by Kenshin Cui on 14-2-16.

    //  Copyright (c) 2014 Kenshin Cui. All rights reserved.

    //


    #import <Foundation/Foundation.h>



    void test1(){

        NSDictionary *dic1=[NSDictionary dictionaryWithObject:@"1" forKey:@"a"];

        NSLog(@"%@",dic1);

        /*结果:

         {

            a = 1;

         }

         */

        

        //常用的方式

        NSDictionary *dic2=[NSDictionary dictionaryWithObjectsAndKeys:

                            @"1",@"a",

                            @"2",@"b",

                            @"3",@"c",

                            nil];

        NSLog(@"%@",dic2);

        /*结果:

         {

             a = 1;

             b = 2;

             c = 3;

         }

         */

        

        

        NSDictionary *dic3=[NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:@"1",@"2", nil] forKeys:[NSArray arrayWithObjects:@"a",@"b", nil]];

        NSLog(@"%@",dic3);

        /*结果:

         {

             a = 1;

             b = 2;

         }

         */

        

        

        //更简单的方式

        NSDictionary *dic4=@{@"1":@"a",@"2":@"b",@"3":@"c"};

        NSLog(@"%@",dic4);

        /*结果:

         {

             1 = a;

             2 = b;

             3 = c;

         }

         */

    }

    void test2(){

        NSDictionary *dic1=[NSDictionary dictionaryWithObjectsAndKeys:

                            @"1",@"a",

                            @"2",@"b",

                            @"3",@"c",

                            @"2",@"d",

                            nil];

        NSLog(@"%zi",[dic1 count]); //结果:4

        NSLog(@"%@",[dic1 valueForKey:@"b"]);//根据键取得值,结果:2

        NSLog(@"%@",dic1[@"b"]);//还可以这样读取,结果:2

        NSLog(@"%@,%@",[dic1 allKeys],[dic1 allValues]);

        /*结果:

         (

             d,

             b,

             c,

             a

         ),(

             2,

             2,

             3,

             1

         )


         */

        

        NSLog(@"%@",[dic1 objectsForKeys:[NSArray arrayWithObjects:@"a",@"e" , nil]notFoundMarker:@"not fount"]);//后面一个参数notFoundMarker是如果找不到对应的key用什么值代替

        /*结果:

         (

             1,

             "not fount"

         )

         */

    }

    void test3(){

        NSDictionary *dic1=[NSDictionary dictionaryWithObjectsAndKeys:

                            @"1",@"a",

                            @"2",@"b",

                            @"3",@"c",

                            @"2",@"d",

                            nil];

        //遍历1

        for (id key in dic1) {//注意对于字典for遍历循环的是key

            NSLog(@"%@=%@",key,[dic1 objectForKey:key]);

        }

        /*结果:

         d=2

         b=2

         c=3

         a=1

         */

        

        //遍历2

        NSEnumerator *enumerator=[dic1 keyEnumerator];//还有值的迭代器[dic1 objectEnumerator]

        id key=nil;

        while (key=[enumerator nextObject]) {

            NSLog(@"%@=%@",key,[dic1 objectForKey:key]);

            

        }

        /*结果:

         d=2

         b=2

         c=3

         a=1

         */

        

        //遍历3

        [dic1 enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {

            NSLog(@"%@=%@",key,obj);

        }];

        /*结果:

         d=2

         b=2

         c=3

         a=1

         */

    }


    void test4(){

        NSMutableDictionary *dic=[NSMutableDictionary dictionaryWithObjectsAndKeys:@"1",@"a",

                                  @"2",@"b",

                                  @"3",@"c",

                                  @"2",@"d",

                                nil];

        [dic removeObjectForKey:@"b"];

        NSLog(@"%@",dic);

        /*结果:

         {

             a = 1;

             c = 3;

             d = 2;

         }

         */

        

        [dic addEntriesFromDictionary:@{@"e":@"7",@"f":@"6"}];

        NSLog(@"%@",dic);

        /*结果:

         {

             a = 1;

             c = 3;

             d = 2;

             e = 7;

             f = 6;

         }

         */

        

        [dic setValue:@"5" forKey:@"a"];

        NSLog(@"%@",dic);

        /*结果:

         {

             a = 5;

             c = 3;

             d = 2;

             e = 7;

             f = 6;

         }

         */

         

        

        //注意,一个字典的keyvalue添加到字典中时计数器+1;字典释放时调用keyvaluerelease一次,计数器-1

    }



    int main(int argc, const char * argv[]) {

        test1();

        test2();

        test3();

        test4();

        return 0;

    }

    注意:同数组一样,不管是可变字典还是不可变字典初始化元素后面必须加上nil以表示结束。

    装箱和拆箱

    其实从上面的例子中我们也可以看到,数组和字典中只能存储对象类型,其他基本类型和结构体是没有办法放到数组和字典中的,当然你也是无法给它们发送消息的(也就是说有些NSObject的方法是无法调用的),这个时候通常会用到装箱(boxing)和拆箱(unboxing)。其实各种高级语言基本上都有装箱和拆箱的过程,例如C#中我们将基本数据类型转化为Object就是一个装箱的过程,将这个Object对象转换为基本数据类型的过程就是拆箱,而且在C#中装箱的过程可以自动完成,基本数据类型可以直接赋值给Object对象。但是在ObjC中装箱的过程必须手动实现,ObjC不支持自动装箱。

    ObjC中我们一般将基本数据类型装箱成NSNumber类型(当然它也是NSObject的子类,但是NSNumber不能对结构体装箱),调用其对应的方法进行转换:

    +(NSNumber *)numberWithChar:(char)value;

    +(NSNumber *)numberWithInt:(int)value;

    +(NSNumber *)numberWithFloat:(float)value;

    +(NSNumber *)numberWithDouble:(double)value;

    +(NSNumber *)numberWithBool:(BOOL)value;

    +(NSNumber *)numberWithInteger:(NSInteger)value;

    拆箱的过程就更加简单了,可以调用如下方法:

    -(char)charValue;

    -(int)intValue;

    -(float)floatValue;

    -(double)doubleValue;

    -(BOOL)boolValue;

    简单看一个例子

    //

    //  main.m

    //  FoundationFramework

    //

    //  Created by Kenshin Cui on 14-2-16.

    //  Copyright (c) 2014 Kenshin Cui. All rights reserved.

    //


    #import <Foundation/Foundation.h>



    /*可以存放基本类型到数组、字典*/

    void test1(){

        //包装类NSNumber,可以包装基本类型但是无法包装结构体类型

        NSNumber *number1=[NSNumber numberWithChar:'a'];//'a'是一个C语言的char类型我们无法放倒NSArray中,但是我们可以通过NSNumber包装

        NSArray *array1=[NSArray arrayWithObject:number1];

        NSLog(@"%@",array1);

        /*结果:

         (

            97

         )

         */

        

        NSNumber *number2= [array1 lastObject];

        NSLog(@"%@",number2);//返回的不是基本类型,结果:97

        

        

        char char1=[number2 charValue];//number转化为char

        NSLog(@"%c",char1); //结果:a

    }


    int main(int argc, const char * argv[]) {

        test1();

        return  0;

    }

    上面我们看到了基本数据类型的装箱和拆箱过程,那么结构体呢?这个时候我们需要引入另外一个类型NSValue,其实上面的NSNumber就是NSValue的子类,它包装了一些基本数据类型的常用装箱、拆箱方法,当要对结构体进行装箱、拆箱操作我们需要使用NSValueNSValue可以对任何数据类型进行装箱、拆箱操作。

    事实上对于常用的结构体Foundation已经为我们提供好了具体的装箱方法:

    +(NSValue *)valueWithPoint:(NSPoint)point;

    +(NSValue *)valueWithSize:(NSSize)size;

    +(NSValue *)valueWithRect:(NSRect)rect;

    对应的拆箱方法:

    -(NSPoint)pointValue;

    -(NSSize)sizeValue;

    -(NSRect)rectValue;

    //

    //  main.m

    //  FoundationFramework

    //

    //  Created by Kenshin Cui on 14-2-16.

    //  Copyright (c) 2014 Kenshin Cui. All rights reserved.

    //


    #import <Foundation/Foundation.h>


    //NSNumberNSValue的子类,而NSValue可以包装任何类型,包括结构体

    void test1(){

        CGPoint point1=CGPointMake(10, 20);

        NSValue *value1=[NSValue valueWithPoint:point1];//对于系统自带类型一般都有直接的方法进行包装

        NSArray *array1=[NSArray arrayWithObject:value1];//放倒数组中

        NSLog(@"%@",array1);

        /*结果:

         (

            "NSPoint: {10, 20}"

         )

         */

        

        NSValue *value2=[array1 lastObject];

        CGPoint point2=[value2 pointValue];//同样对于系统自带的结构体有对应的取值方法(例如本例pointValue

        NSLog(@"x=%f,y=%f",point2.x,point2.y);//结果:x=10.000000,y=20.000000

    }



    int main(int argc, const char * argv[]) {

        test1();

        return  0;

    }

     

    那么如果是我们自定义的结构体类型呢,这个时候我们需要使用NSValue如下方法进行装箱:

    +(NSValue *)valueWithBytes:(const void *)value objCType:(const char *)type;

    调用下面的方法进行拆箱:

    -(void)getValue:(void *)value;

    //

    //  main.m

    //  FoundationFramework

    //

    //  Created by Kenshin Cui on 14-2-16.

    //  Copyright (c) 2014 Kenshin Cui. All rights reserved.

    //


    #import <Foundation/Foundation.h>


    typedef struct {

        int year;

        int month;

        int day;

    } Date;



    //NSNumberNSValue的子类,而NSValue可以包装任何类型,包括结构体

    void test1(){

        //如果我们自己定义的结构体包装

        Date date={2014,2,28};

        char *type=@encode(Date);

        NSValue *value3=[NSValue value:&date withObjCType:type];//第一参数传递结构体地址,第二个参数传递类型字符串

        NSArray *array2=[NSArray arrayWithObject:value3];

        NSLog(@"%@",array2);

        /*结果:

         (

            "<de070000 02000000 1c000000>"

         )

         */

        

        Date date2;

        [value3 getValue:&date2];//取出对应的结构体,注意没有返回值

        //[value3 objCType]//取出包装内容的类型

        NSLog(@"%i,%i,%i",date2.year,date2.month,date2.day); //结果:2014,2,28

        

    }



    int main(int argc, const char * argv[]) {

        test1();

        return  0;

    }

    扩展1-NSNull

    通过前面的介绍大家都知道无论在数组还是在字典中都必须以nil结尾,否则数组或字典无法判断是否这个数组或字典已经结束(与C语言中的字符串比较类似,C语言中定义字符串后面必须加一个”\0”)。但是我们有时候确实想在数据或字典中存储nil值而不是作为结束标记怎么办呢?这个时候需要使用NSNull,这个类是一个单例,只有一个null方法。简单看一下:

    //

    //  main.m

    //  FoundationFramework

    //

    //  Created by Kenshin Cui on 14-2-16.

    //  Copyright (c) 2014 Kenshin Cui. All rights reserved.

    //


    #import <Foundation/Foundation.h>




    int main(int argc, const char * argv[]) {

        

        NSNull *nl=[NSNull null];//注意这是一个对象,是一个单例,只有一个方法null创建一个对象

        NSNull *nl2=[NSNull null];

        NSLog(@"%i",nl==nl2);//由于是单例所以地址相等,结果:1

        

        NSArray *array1=[NSArray arrayWithObjects:@"abc",nl,@123, nil];

        NSLog(@"%@",array1);

        /*结果:

         (

             abc,

             "<null>",

             123

         )

         */


        return  0;

    }

     

    扩展2-@符号

    我们知道在ObjC中很多关键字前都必须加上@符号,例如@protocol@property等,当然ObjC中的字符串必须使用@符号,还有就是%@可以表示输出一个对象。其实@符号在新版的ObjC中还有一个作用:装箱。

    相信聪明的童鞋在前面的例子中已经看到了,这里简单的介绍一下(在下面的演示中你也将看到很多ObjC新特性)。

    //

    //  main.m

    //  FoundationFramework

    //

    //  Created by Kenshin Cui on 14-2-16.

    //  Copyright (c) 2014 Kenshin Cui. All rights reserved.

    //


    #import <Foundation/Foundation.h>


    typedef enum {

        spring,

        summer,

        autumn,

        winter

    } Season;


    int main(int argc, const char * argv[]) {

        /*装箱*/

        NSNumber *number1=@100;

        NSArray *array1=[NSArray arrayWithObjects:number1,@"abc",@16,@'A',@16.7,@YES, nil];

        NSLog(@"%@",array1);

        /*结果:

         (

             100,

             abc,

             16,

             65,

             "16.7"

             1

         )

         */

        NSNumber *number2=@(1+2*3);

        NSLog(@"%@",number2); //结果:7

        NSNumber *number3=@(autumn);

        NSLog(@"%@",number3); //结果:2

        


        NSArray *array2=@[@"abc",@16,@'A',@16.7,@YES];//使用这种方式最后不用添加nil值了

        NSLog(@"%@",array2[2]); //结果:65

        NSMutableArray *array3=[NSMutableArray arrayWithArray:array2];

        array3[0]=@"def";

        NSLog(@"%@",array3[0]); //结果:def

        

        NSDictionary *dic1=@{@"a":@123,@"b":@'c',@"c":@YES};

        NSLog(@"%@",dic1);

        /*结果:

         {

             a = 123;

             b = 99;

             c = 1;

         }

         */

        NSMutableDictionary *dic2=[NSMutableDictionary dictionaryWithDictionary:dic1];

        dic2[@"a"]=@456;

        NSLog(@"%@",dic2[@"a"]);//结果:456


        return 0;

    }

    反射

    由于ObjC动态性,在ObjC中实现反射可以说是相当简单,下面代码中演示了常用的反射操作,具体作用也都在代码中进行了注释说明:

    Account.h

    //

    //  Account.h

    //  FoundationFramework

    //

    //  Created by Kenshin Cui on 14-2-16.

    //  Copyright (c) 2014 Kenshin Cui. All rights reserved.

    //


    #import <Foundation/Foundation.h>


    @interface Account : NSObject


    @property (nonatomic,assign) double balance;


    @end

    Account.m

    //

    //  Account.m

    //  FoundationFramework

    //

    //  Created by Kenshin Cui on 14-2-16.

    //  Copyright (c) 2014 Kenshin Cui. All rights reserved.

    //


    #import "Account.h"


    @implementation Account


    @end

    Person.h

    //

    //  Person.h

    //  FoundationFramework

    //

    //  Created by Kenshin Cui on 14-2-16.

    //  Copyright (c) 2014 Kenshin Cui. All rights reserved.

    //


    #import <Foundation/Foundation.h>

    @class Account;


    @interface Person : NSObject


    @property (nonatomic,copy) NSString *name;

    @property (nonatomic,retain) Account *account;


    -(Person *)initWithName:(NSString *)name;


    +(Person *)personWithName:(NSString *)name;


    -(void)showMessage:(NSString *)infomation;


    //自己实现对象比较方法

    -(NSComparisonResult)comparePerson:(Person *)person;

    @end

    Person.m

    //

    //  Person.m

    //  FoundationFramework

    //

    //  Created by Kenshin Cui on 14-2-16.

    //  Copyright (c) 2014 Kenshin Cui. All rights reserved.

    //


    #import "Person.h"


    @implementation Person


    -(Person *)initWithName:(NSString *)name{

        if(self=[super init]){

            self.name=name;

        }

        return self;

    }


    +(Person *)personWithName:(NSString *)name{

        Person *person=[[Person alloc]initWithName:name];

        return person;

    }


    -(void)showMessage:(NSString *)infomation{

        NSLog(@"My name is %@,the infomation is \"%@\".",_name,infomation);

    }


    //自己实现对象比较方法

    -(NSComparisonResult)comparePerson:(Person *)person{

        return [_name compare:person.name];

    }


    -(NSString *)description{

        return [NSString stringWithFormat:@"name=%@",_name];

    }


    @end

    main.m

    //

    //  main.m

    //  FoundationFramework

    //

    //  Created by Kenshin Cui on 14-2-16.

    //  Copyright (c) 2014 Kenshin Cui. All rights reserved.

    //


    #import <Foundation/Foundation.h>

    #import "Person.h"



    int main(int argc, const char * argv[]) {

        /*常用方法*/

        Person *person1=[Person personWithName:@"Kenshin"];

        NSLog(@"%i",[person1 isKindOfClass:[NSObject class]]); //判断一个对象是否为某种类型(如果是父类也返回YES),结果:1

        NSLog(@"%i",[person1 isMemberOfClass:[NSObject class]]); //判断一个对象是否是某个类的实例化对象,结果:0

        NSLog(@"%i",[person1 isMemberOfClass:[Person class]]); //结果:1

        NSLog(@"%i",[person1 conformsToProtocol:@protocol(NSCopying)]);//是否实现了某个协议,结果:0

        NSLog(@"%i",[person1 respondsToSelector:@selector(showMessage:)]);//是否存在某个方法,结果:1

        

        [person1 showMessage:@"Hello,world!"];//直接调用一个方法

        [person1 performSelector:@selector(showMessage:) withObject:@"Hello,world!"];

        //动态调用一个方法,注意如果有参数那么参数类型只能为ObjC对象,并且最多只能有两个参数


        

        /*反射*/

        //动态生成一个类

        NSString *className=@"Person";

        Class myClass=NSClassFromString(className);//根据类名生成类

        Person *person2=[[myClass alloc]init]; //实例化

        person2.name=@"Kaoru";

        NSLog(@"%@",person2);//结果:name=Kaoru


        //类转化为字符串

        NSLog(@"%@,%@",NSStringFromClass(myClass),NSStringFromClass([Person class])); //结果:Person,Person


        //调用方法

        NSString *methodName=@"showMessage:";

        SEL mySelector=NSSelectorFromString(methodName);

        Person *person3=[[myClass alloc]init];

        person3.name=@"Rosa";

        [person3 performSelector:mySelector withObject:@"Hello,world!"]; //结果:My name is Rosa,the infomation is "Hello,world!".


        //方法转化为字符串

        NSLog(@"%@",NSStringFromSelector(mySelector)); //结果:showMessage:

        

        return 0;

    }

    拷贝

    对象拷贝操作也比较常见,在ObjC中有两种方式的拷贝:copymutablecopy,这两中方式都将产生一个新的对象,只是后者产生的是一个可变对象。在ObjC中如果要想实现copy或者mutablecopy操作需要实现NSCopy或者NSMutableCopy协议,拷贝操作产生的新的对象默认引用计数器是1,在非ARC模式下我们应该对这个对象进行内存管理。在熟悉这两种操作之前我们首先需要弄清两个概念:深复制(或深拷贝)和浅复制(或浅拷贝)。

    • 浅复制:在执行复制操作时,对于对象中每一层(对象中包含的对象,例如说属性是某个对象类型)复制都是指针复制(如果从引用计数器角度出发,那么每层对象的引用计数器都会加1)。
    • 深复制:在执行复制操作时,至少有一个对象的复制是对象内容复制(如果从引用计数器角度出发,那么除了对象内容复制的那个对象的引用计数器不变,其他指针复制的对象其引用计数器都会加1)。

    注:

    指针拷贝:拷贝的是指针本身(也就是具体对象的地址)而不是指向的对象内容本身。

    对象复制:对象复制指的是复制内容是对象本身而不是对象的地址。

    完全复制:上面说了深复制和浅复制,既然深复制是至少一个对象复制是对象内容复制,那么如果所有复制都是对象内容复制那么这个复制就叫完全复制。

    对比copymutablecopy其实前面我们一直还用到一个操作是retain,它们之间的关系如下:

    retain:始终采取浅复制,引用计数器会加1,返回的对象和被复制对象是同一个对象1(也就是说这个对象的引用多了一个,或者说是指向这个对象的指针多了一个);

    copy:对于不可变对象copy采用的是浅复制,引用计数器加1(其实这是编译器进行了优化,既然原来的对象不可变,复制之后的对象也不可变那么就没有必要再重新创建一个对象了);对于可变对象copy采用的是深复制,引用计数器不变(原来的对象是可变,现在要产生一个不可变的当然得重新产生一个对象);

    mutablecopy:无论是可变对象还是不可变对象采取的都是深复制,引用计数器不变(如果从一个不可变对象产生一个可变对象自然不用说两个对象绝对不一样肯定是深复制;如果从一个可变对象产生出另一个可变对象,那么当其中一个对象改变自然不希望另一个对象改变,当然也是深复制)。

    注:

    可变对象:当值发生了改变,那么地址也随之发生改变;

    不可变对象:当值发生了改变,内容首地址不发生变化;

    引用计数器:用于计算一个对象有几个指针在引用(有几个指针变量指向同一个内存地址);

     

    //

    //  main.m

    //  FoundationFramework

    //

    //  Created by Kenshin Cui on 14-2-16.

    //  Copyright (c) 2014 Kenshin Cui. All rights reserved.

    //


    #import <Foundation/Foundation.h>



    void test1(){

        NSString *name=@"Kenshin";

        NSString *str1=[NSString stringWithFormat:@"I'm %@.",name];//注意此时str1的计数器是1

        NSLog(@"%lu",[str1 retainCount]); //结果:1

        

        

        NSMutableString *str2=[str1 mutableCopy];//注意此时str2的计数器为1str1的计数器还是1

        //NSMutableString *str5 =CFRetain((__bridge CFTypeRef)str2);

        NSLog(@"retainCount(str1)=%lu,retainCount(str2)=%lu",[str1 retainCount],[str2 retainCount]);

        //结果:retainCount(str1)=1,retainCount(str2)=1

        

        

        [str2 appendString:@"def"];//改变str2str1不变

        NSLog(@"%zi",str1==str2);//二者不是向同一个对象,结果:0

        NSLog(@"str1=%@",str1); //结果:str1=I'm Kenshin.

        NSLog(@"str2=%@",str2); //结果:str2=I'm Kenshin.def

        

        

        NSLog(@"str1's %lu",[str1 retainCount]);

        NSString *str3=[str1 copy];//str3不是产生的新对象而是复制了对象指针,但是str1的计数器+1(当然既然str3同样指向同一个对象,那么如果计算str3指向的对象引用计数器肯定等于str1的对象引用计数器)

        NSLog(@"%zi",str1==str3);//二者相等指向同一个对象,结果:1

        NSLog(@"retainCount(str1)=%lu,retainCount(str3)=%lu",str1.retainCount,str3.retainCount);

        //结果:retainCount(str1)=2,retainCount(str3)=2

        

        //需要注意的是使用copymutableCopy是深复制还是浅复制不是绝对,关键看由什么对象产生什么样的对象

        NSString *str4=[str2 copy];//NSMutableString产生了NSString,二者类型都不同肯定是深拷贝,此时str2的计数器还是1str4的计数器也是1

        [str2 appendString:@"g"];//改变原对象不影响str4

        NSLog(@"%zi",str2==str4); //结果:0

        NSLog(@"str2=%@",str2); //结果:str2=I'm Kenshin.defg

        NSLog(@"str4=%@",str4); //结果:str4=I'm Kenshin.def


        

        [str1 release];

        str1=nil;

        [str3 release];//其实这里也可以调用str1再次release,因为他们两个指向的是同一个对象(但是一般不建议那么做,不容易理解)

        str3=nil;

        

        [str2 release];

        str2=nil;

        [str4 release];

        str4=nil;

        

        //上面只有一种情况是浅拷贝:不可变对象调用copy方法

        

    }


    int main(int argc,char *argv[]){

        test1();

        return 0;

    }

    为了方便大家理解上面的代码,这里以图形画出str1str2str3str4在内存中的存储情况:


    从上面可以清楚的看到str1str3同时指向同一个对象,因此这个对象的引用计数器是2(可以看到两箭头指向那个对象)str2str4都是两个新的对象;另外ObjC引入对象拷贝是为了改变一个对象不影响另一个对象,但是我们知道NSString本身就不能改变那么即使我重新复制一个对象也没有任何意义,因此为了性能着想如果通过copy方法产生一个NSStringObjC不会再复制一个对象而是将新变量指向同一个对象。

    注意网上很多人支招在ARC模式下可以利用_objc_rootRetainCount()或者CFGetRetainCount()取得retainCount都是不准确的,特别是在对象拷贝操作之后你会发现二者取值也是不同的,因此如果大家要查看retainCount最好还是暂时关闭ARC

    要想支持copy或者mutablecopy操作那么对象必须实现NSCoping协议并实现-(id)copyWithZone:(NSZone*)zone方法,在Foundation中常用的可复制对象有:NSNumberNSStringNSMutableStringNSArrayNSMutableArrayNSDictionaryNSMutableDictionary。下面看一下如何让自定义的类支持copy操作:

    Person.h

    //

    //  Person.h

    //  FoundationFramework

    //

    //  Created by Kenshin Cui on 14-2-16.

    //  Copyright (c) 2014 Kenshin Cui. All rights reserved.

    //


    #import <Foundation/Foundation.h>

    @class Account;


    @interface Person : NSObject


    @property  NSMutableString *name;

    @property (nonatomic,assign) int age;



    @end

    Person.m

    //

    //  Person.m

    //  FoundationFramework

    //

    //  Created by Kenshin Cui on 14-2-16.

    //  Copyright (c) 2014 Kenshin Cui. All rights reserved.

    //


    #import "Person.h"


    @implementation Person



    -(NSString *)description{

        return [NSString stringWithFormat:@"name=%@,age=%i",_name,_age];

    }


    //实现copy方法

    -(id)copyWithZone:(NSZone *)zone{

        //注意zone是系统已经分配好的用于存储当前对象的内存

        //注意下面创建对象最好不要用[[Person allocWithZone:zone]init],因为子类如果没有实现该方法copy时会调用父类的copy方法,此时需要使用子类对象初始化如果此时用self就可以表示子类对象,还有就是如果子类调用了父类的这个方法进行重写copy也需要调用子类对象而不是父类Person

        Person *person1=[[[self class] allocWithZone:zone]init];

        person1.name=_name;

        person1.age=_age;

        return person1;

    }


    @end

    main.m

    //

    //  main.m

    //  FoundationFramework

    //

    //  Created by Kenshin Cui on 14-2-16.

    //  Copyright (c) 2014 Kenshin Cui. All rights reserved.

    //


    #import <Foundation/Foundation.h>

    #import "Account.h"

    #import "Person.h"


    void test1(){

        Person *person1=[[Person alloc]init];

        NSMutableString *str1=[NSMutableString stringWithString:@"Kenshin"];

        person1.name=str1;

        //由于name定义的时候使用属性参数采用的是copy策略,而根据前面的知识我们知道NSMutableStringcopy策略采用的是对象内容复制,因此如果修改str1不会改变person1.name

        [str1 appendString:@" Cui"];

        NSLog(@"%@",str1);//结果:Kenshin Cui

        NSLog(@"%@",person1.name); //结果:Kenshin

        

    }


    void test2(){

        Person *person1=[[Person alloc]init];

        person1.name=[NSMutableString stringWithString:@"Kenshin"];

        person1.age=28;

        Person *person2=[person1 copy];

        NSLog(@"%@",person1); //结果:name=Kenshin,age=0

        NSLog(@"%@",person2); //结果:name=Kenshin,age=0

        

        [person2.name appendString:@" Cui"];

        

        NSLog(@"%@",person1);//结果:name=Kenshin Cui,age=28

        NSLog(@"%@",person2);//结果:name=Kenshin Cui,age=28

    }


    int main(int argc,char *argv[]){

        test1();

        test2();

        return 0;

    }

    在上面的代码中重点说一下test2这个方法,在test2方法中我们发现当修改了person2.name属性之后person1.name也改变了,这是为什么呢?我们可以看到在Person.m中自定义实现了copy方法,同时实现了一个浅拷贝。之所以说是浅拷贝主要是因为我们的name属性参数是直接赋值完成的,同时由于name属性定义时采用的是assign参数(默认为assign),所以当通过copy创建了person2之后其实person2对象的name属性和person1指向同一个NSMutableString对象。通过图形表示如下:


    上面test2的写法纯属为了让大家了解复制的原理和本质,实际开发中我们很少会遇到这种情况,首先我们一般定义name的话可能用的是NSString类型,根本也不能修改;其次我们定义字符串类型的话一般使用(copy)参数,同样可以避免这个问题(因为NSMutableStringcopy是深复制)。那么如果我们非要使用NSMutabeString同时不使用属性的copy参数如何解决这个问题呢?答案就是使用深复制,将-(id)copyWithZone:(NSZone *)zone方法中person1.name=_name改为,person1.name=[_name copy];person1.name=[_name mutablecopy]即可,这样做也正好满足我们上面对于深复制的定义。

    补充-NSString的引用计数器

    在好多语言中字符串都是一个特殊的对象,在ObjC中也不例外。NSString作为一个对象类型存储在堆中,多数情况下它跟一般的对象类型没有区别,但是这里我们需求强调一点那就是字符串的引用计数器。

    //

    //  main.m

    //  FoundationFramework

    //

    //  Created by Kenshin Cui on 14-2-16.

    //  Copyright (c) 2014 Kenshin Cui. All rights reserved.

    //


    #import <Foundation/Foundation.h>



    int main(int argc,char *argv[]){

        

        NSString *str1=@"Kenshin";

        NSLog(@"retainCount(str1)=%i",(unsigned long)str1.retainCount); //结果:-1

        [str1 retain];

        NSLog(@"retainCount(str1)=%i",(unsigned long)str1.retainCount); //结果:-1

        

        NSString *str2=[NSString stringWithString:@"Kaoru"];

        NSLog(@"retainCount(str2)=%i",str2.retainCount); //结果:-1

        [str1 retain];

        NSLog(@"retainCount(str2)=%i",str2.retainCount); //结果:-1

        NSString *str2_1=[NSString stringWithString:[NSString stringWithFormat:@"Kaoru %@",@"sun"]];

        NSLog(@"retainCount(str2_1)=%i",str2_1.retainCount);//结果:

        [str2_1 release];

        [str2_1 release];

        

        

        

        NSString *str3=[NSString stringWithFormat:@"Rosa %@",@"Sun"];

        NSLog(@"retainCount(str3)=%i",str3.retainCount); //结果:1

        [str3 retain];

        NSLog(@"retainCount(str3)=%i",str3.retainCount); //结果:2

        [str3 release];

        [str3 release];

        

        NSString *str4=[NSString stringWithUTF8String:"Jack"];

        NSLog(@"retainCount(str4)=%i",str4.retainCount); //结果:1

        [str4 retain];

        NSLog(@"retainCount(str4)=%i",str4.retainCount); //结果:2

        [str4 release];

        [str4 release];

        

        NSString *str5=[NSString stringWithCString:"Tom" encoding:NSUTF8StringEncoding];

        NSLog(@"retainCount(str5)=%i",str5.retainCount); //结果:1

        [str5 retain];

        NSLog(@"retainCount(str5)=%i",str5.retainCount); //结果:2

        [str5 release];

        [str5 release];

        

        

        

        NSMutableString *str6=@"Jerry";

        NSLog(@"retainCount(str6)=%i",str6.retainCount); //结果:-1

        [str6 retain];

        NSLog(@"retainCount(str6)=%i",str6.retainCount); //结果:-1

        [str6 release];

        [str6 release];

        

        NSMutableArray *str7=[NSMutableString stringWithString:@"Lily"];

        NSLog(@"retainCount(str7)=%i",str7.retainCount); //结果:1

        [str7 retain];

        NSLog(@"retainCount(str7)=%i",str7.retainCount); //结果:2

        [str7 release];

        [str7 release];


        

        return 0;

    }

    看完上面的例子如果不了解NSString的处理你也许会有点奇怪(注意上面的代码请在Xcode5下运行)?请看下面的解释

    • str1是一个字符串常量,它存储在常量区,系统不会对它进行引用计数,因此无论是初始化还是做retain操作其引用计数器均为-1
    • str3str4str5创建的对象同一般对象类似,存储在堆中,系统会对其进行引用计数;
    • 采用stringWithString定义的变量有些特殊,当后面的字符串是字符串常量,则它本身就作为字符串常用量存储(str2),类似于str1;如果后面的参数是通过类似于str3str4str5的定义,那么它本身就是一个普通对象,只是后面的对象引用计数器默认为1,当给它赋值时会做一次拷贝操作(浅拷贝),引用计数器加1,所有str2_1引用计数器为2
    • str6其实和str1类似,虽然定义的是可变数组,但是它的本质还是字符串常量,事实上对于可变字符串只有为字符串常量时引用计数器才为-1,其他情况它的引用计数器跟一般对象完全一致;

    后记:注意上面这段代码的运行结果是在Xcode5中运行的结果,事实上针对最新的Xcode6由于LLVM的优化,只有str2_1str7的引用计数器为1str7 retain一次后第二次为2),其他均为-1

    文件操作

    在今天的最后一节内容中让我们看一下Foundation中文件操作,下面将以一个例子进行说明:

    //

    //  main.m

    //  FoundationFramework

    //

    //  Created by Kenshin Cui on 14-2-16.

    //  Copyright (c) 2014 Kenshin Cui. All rights reserved.

    //


    #import <Foundation/Foundation.h>


    /*目录操作*/

    void test1(){

        //文件管理器是专门用于文件管理的类

        NSFileManager *manager=[NSFileManager defaultManager];

        

        //获得当前程序所在目录(当然可以改变)

        NSString *currentPath=[manager currentDirectoryPath];

        NSLog(@"current path is :%@",currentPath);

        //结果:/Users/kenshincui/Library/Developer/Xcode/DerivedData/FoundationFramework-awxjohcpgsqcpsanqofqogwbqgbx/Build/Products/Debug

        

        //创建目录

        NSString *myPath=@"/Users/kenshincui/Desktop/myDocument";

        BOOL result= [manager createDirectoryAtPath:myPath withIntermediateDirectories:YES attributes:nil error:nil];

        if(result==NO){

            NSLog(@"Couldn't create directory!");

        }

        

        //目录重命名,如果需要删除目录只要调用removeItemAtPath:<#(NSString *)#> error:<#(NSError **)#>

        NSError *error;

        NSString *newPath=@"/Users/kenshincui/Desktop/myNewDocument";

        if([manager moveItemAtPath:myPath toPath:newPath error:&error]==NO){

            NSLog(@"Rename directory failed!Error infomation is:%@",error);

        }

        

        //改变当前目录

        if([manager changeCurrentDirectoryPath:newPath]==NO){

            NSLog(@"Change current directory failed!");

        }

        NSLog(@"current path is :%@",[manager currentDirectoryPath]);

        //结果:current path is :/Users/kenshincui/Desktop/myNewDocument

        

        //遍历整个目录

        NSString *path;

        NSDirectoryEnumerator *directoryEnumerator= [manager enumeratorAtPath:newPath];

        while (path=[directoryEnumerator nextObject]) {

            NSLog(@"%@",path);

        }

        /*结果:

         documents

         est.txt

        */

        

        //或者这样遍历

        NSArray *paths= [manager contentsOfDirectoryAtPath:newPath error:nil];

        NSObject *p;

        for (p in paths) {

            NSLog(@"%@",p);

        }

        /*结果:

         documents

         est.txt

         */

    }


    /*文件操作*/

    void test2(){

        NSFileManager *manager=[NSFileManager defaultManager];

        NSString *filePath=@"/Users/kenshincui/Desktop/myNewDocument/test.txt";

        NSString *filePath2=@"/Users/kenshincui/Desktop/test.txt";

        NSString *newPath=@"/Users/kenshincui/Desktop/myNewDocument/test2.txt";

        

        //判断文件是否存在,这个方法也可以判断目录是否存在,这要后面的参数设置位YES

        if ([manager fileExistsAtPath:filePath isDirectory:NO]) {

            NSLog(@"File exists");

        }

        

        //文件是否可读

        if([manager isReadableFileAtPath:filePath]){

            NSLog(@"File is readable!");

        }

        

        //判断两个文件内容是否相等

        if ([manager contentsEqualAtPath:filePath andPath:filePath2]) {

            NSLog(@"file1 equals file2");

        }

        

        //文件重命名,方法类似于目录重命名

        if (![manager moveItemAtPath:filePath toPath:newPath error:nil]) {

            NSLog(@"Rename file1 failed!");

        }

        

        //文件拷贝

        NSString *filePath3=@"/Users/kenshincui/Desktop/test3.txt";

        if(![manager copyItemAtPath:newPath toPath:filePath3 error:nil]){

            NSLog(@"Copy failed!");

        }

        

        //读取文件属性

        NSDictionary *attributes;

        if ((attributes=[manager attributesOfItemAtPath:newPath error:nil])==nil) {

            NSLog(@"Read attributes failed!");

        }

        for (NSObject *key in attributes) {

            NSLog(@"%@=%@",key,attributes[key]);

        }

        /*结果:

             NSFileOwnerAccountID=501

             NSFileHFSTypeCode=0

             NSFileSystemFileNumber=1781953

             NSFileExtensionHidden=0

             NSFileSystemNumber=16777218

             NSFileSize=27

             NSFileGroupOwnerAccountID=20

             NSFileOwnerAccountName=kenshincui

             NSFileCreationDate=2014-07-28 11:47:58 +0000

             NSFilePosixPermissions=420

             NSFileHFSCreatorCode=0

             NSFileType=NSFileTypeRegular

             NSFileExtendedAttributes={

             "com.apple.TextEncoding" = <7574662d 383b3133 34323137 393834>;

             }

             NSFileGroupOwnerAccountName=staff

             NSFileReferenceCount=1

             NSFileModificationDate=2014-07-28 11:47:58 +0000

         */

        

        //删除文件

        [manager removeItemAtPath:newPath error:nil];

        

    }

    //文件操作--文件内容操作(NSData,非结构化字节流对象,有缓冲区管理机制,可用于网络传输)

    void test3(){

        NSFileManager *manager=[NSFileManager defaultManager];

        NSString *filePath=@"/Users/kenshincui/Desktop/myNewDocument/test2.txt";

        NSData *data=[manager contentsAtPath:filePath];

        NSLog(@"%@",data);//存储的是二进制字节流

        //结果:<68656c6c 6f20776f 726c642c e4b896e7 958ce4bd a0e5a5bd efbc81>

        

        //NSData转化成字符串

        NSString *str1=[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];

        NSLog(@"%@",str1);

        //结果:hello world,世界你好!

        

        //字符串转化成NSData

        NSString *str2=@"Kenshin";

        NSData *data2=[str2 dataUsingEncoding:NSUTF8StringEncoding];

        NSLog(@"%@",data2);

        

        //当然一般如果仅仅是简单读取文件内容,直接用户NSString方法即可

        NSString *content=[NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];

        NSLog(@"%@",content);

        //结果:hello world,世界你好!

        

    }

    //文件操作--细粒度控制文件,文件操作柄

    void test4(){

        NSFileManager *manager=[NSFileManager defaultManager];

        NSString *filePath=@"/Users/kenshincui/Desktop/myNewDocument/test2.txt";

        

        //以只读方式打开文件

        NSFileHandle *fileHandle=[NSFileHandle fileHandleForReadingAtPath:filePath];//注意这个方法返回类型为instancetype,也就是说对于上面的NSFileHandle它的返回类型也是NSFileHandle

        NSData *data= [fileHandle readDataToEndOfFile];//完整读取文件

        NSString *newPath=@"/Users/kenshincui/Desktop/test4.txt";

        [manager createFileAtPath:newPath contents:nil attributes:nil];

        NSFileHandle *fileHandle2=[NSFileHandle fileHandleForWritingAtPath:newPath];//以可写方式打开文件

        [fileHandle2 writeData:data];//写入文件内容

        

        [fileHandle2 closeFile];//关闭文件


        

        //定位到指定位置,默认在文件开头

        [fileHandle seekToFileOffset:12];

        NSData *data2= [fileHandle readDataToEndOfFile];

        NSLog(@"data2=%@",[[NSString alloc]initWithData:data2 encoding:NSUTF8StringEncoding]);

        //结果:data2=世界你好!

        

        [fileHandle seekToFileOffset:6];

        NSData *data3=[fileHandle readDataOfLength:5];

        NSLog(@"data3=%@",[[NSString alloc]initWithData:data3 encoding:NSUTF8StringEncoding]);

        //结果:data3=world

        

        [fileHandle closeFile];

        

    }


    //文件路径

    void test5(){

        NSString *filePath=@"/Users/kenshincui/Desktop/myDocument";

        NSString *filePath2=@"/Users/kenshincui/Desktop/test.txt";


        //临时文件所在目录

        NSString *path=NSTemporaryDirectory();

        NSLog(@"temporary directory is :%@",path);

        //结果:/var/folders/h6/lss6gncs509c2pgzgty3wd_40000gn/T/


        NSString *lastComponent= [filePath lastPathComponent];

        NSLog(@"%@",lastComponent); //结果:myDocument

        

        NSLog(@"%@",[filePath stringByDeletingLastPathComponent]);

        //结果:/Users/kenshincui/Desktop

        NSLog(@"%@",[filePath stringByAppendingPathComponent:@"Pictrues"]);

        //结果:/Users/kenshincui/Desktop/myDocument/Pictrues

        NSLog(@"%@",[filePath2 pathExtension]);

        //结果:txt

        

        [[filePath pathComponents] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {

            NSLog(@"%i=%@",idx,obj);

        }];

        /*结果:

         0=/

         1=Users

         2=kenshincui

         3=Desktop

         4=myDocument

         */

        

        

    }


    //文件操作--NSURL

    void test6(){

        NSURL *url=[NSURL URLWithString:@"http://developer.apple.com"];

        NSString *str1=[NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];

        NSLog(@"%@",str1);

    }


    //文件操作--NSBundle,程序包,一般用于获取Resource中的资源(当然由于当前并非IOS应用没有程序包,只是表示当前程序运行路径)

    //ios中经常用于读取应用程序中的资源文件,如图片、声音、视频等

    void test7(){

        //在程序包所在目录创建一个文件

        NSFileManager *manager=[NSFileManager defaultManager];

        NSString *currentPath=[manager currentDirectoryPath];

        NSLog(@"current path is :%@",currentPath);

        //结果:current path is :/Users/kenshincui/Library/Developer/Xcode/DerivedData/FoundationFramework-awxjohcpgsqcpsanqofqogwbqgbx/Build/Products/Debug

        NSString *filePath=[currentPath stringByAppendingPathComponent:@"test.txt"];

        [manager createFileAtPath:filePath contents:[@"Hello,world!" dataUsingEncoding:NSUTF8StringEncoding] attributes:nil];

        

        

        //利用NSBundle在程序包所在目录查找对应的文件

        NSBundle *bundle=[NSBundle mainBundle];//主要操作程序包所在目录

        //如果有test.txt则返回路径,否则返回nil

        NSString *path=[bundle pathForResource:@"test" ofType:@"txt"];//也可以写成:[bundle pathForResource:@"instructions.txt" ofType:nil];

        NSLog(@"%@",path);

        //结果:/Users/kenshincui/Library/Developer/Xcode/DerivedData/FoundationFramework-awxjohcpgsqcpsanqofqogwbqgbx/Build/Products/Debug/test.txt

        NSLog(@"%@",[NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil]);

        //结果:Hello,world!

        

        //假设我们在程序运行创建一个Resources目录,并且其中新建pic.jpg,那么用下面的方法获得这个文件完整路径

        NSString *path1= [bundle pathForResource:@"pic" ofType:@"jpg" inDirectory:@"Resources"];

        NSLog(@"%@",path1);

        //结果:/Users/kenshincui/Library/Developer/Xcode/DerivedData/FoundationFramework-awxjohcpgsqcpsanqofqogwbqgbx/Build/Products/Debug/Resources/pic.jpg

    }


    int main(int argc,char *argv[]){


        test1();

        test2();

        test3();

        test4();

        test5();

        test6();

        test7();

        

        return 0;

    }

    归档

    归档,在其他语言中又叫序列化,就是将对象保存到硬盘;解档,在其他语言又叫反序列化就是将硬盘文件还原成对象。其实归档就是数据存储的过程,在IOS中数据的存储有五种方式:

    1. xml属性列表(plist归档)
    2. NSUserDefaults(偏好设置)
    3. NSKeyedArchiver归档(加密形式)
    4. SQLite3(嵌入式数据库)
    5. Core Data(面向对象方式的嵌入式数据库)

    当然关于245点不是我们今天介绍的重点,这个在IOS开发过程中我们会重点说到。

    xml属性列表

    首先我们先来看一下xml属性列表,xml属性列表进行归档的方式是将对象存储在一个plist文件中,这个操作起来比较简单,其实相当于xml序列化。但是同时它也有缺点:一是这种方式是明文保存的;二是这种方式操作的对象有限,只有NSArrayNSMutableArrayNSDictionaryNSMutableDictionary支持(归档时只要调用对应的writeToFile方法即可,解档调用arrayWithContentsOfFiledictionaryWithContentsOfFile,注意像NSStringNSNumberNSData即使有这个方法它存储的也不是xml格式)。

    //

    //  main.m

    //  FoundationFramework

    //

    //  Created by Kenshin Cui on 14-2-16.

    //  Copyright (c) 2014 Kenshin Cui. All rights reserved.

    //


    #import <Foundation/Foundation.h>


    //xml属性

    void test1(){

        //数组

        NSString *path=@"/Users/kenshincui/Desktop/arrayXml.plist";

        NSArray *array1=@[@"Kenshin",@"Kaoru",@"Rosa"];

        [array1 writeToFile:path atomically:YES];

        

        NSArray *array2=[NSArray arrayWithContentsOfFile:path];

        [array2 enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {

            NSLog(@"array2[%lu]=%@",idx,obj);

        }];

        /*结果:

         array1[0]=Kenshin

         array1[1]=Kaoru

         array1[2]=Rosa

         */

        

        

        //字典

        NSString *path2=@"/Users/kenshincui/Desktop/dicXml.plist";

        NSDictionary *dic1=@{@"name":@"Kenshin",@"age":@28,@"height":@172.5};

        [dic1 writeToFile:path2 atomically:YES];

        

        NSDictionary *dic2=[NSDictionary dictionaryWithContentsOfFile:path2];

        [dic2 enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {

            NSLog(@"dic2[%@]=%@",key,obj);

        }];

        /*结果:

         dic2[height]=172.5

         dic2[age]=28

         dic2[name]=Kenshin

         */

    }


    int main(int argc,char *argv[]){

        

        test1();

        

        return 0;

    }

    生成的文件如下



    NSKeyedArchiver归档

    如果要针对更多对象归档或者需要归档时能够加密的话就需要使用NSKeyedArchiver进行归档和解档,使用这种方式归档的范围更广而且归档内容是密文存储。从归档范围来讲NSKeyedArchiver适合所有ObjC对象,但是对于自定义对象我们需要实现NSCoding协议;从归档方式来讲NSKeyedArchiver分为简单归档和复杂对象归档,简单归档就是针对单个对象可以直接将对象作为根对象(不用设置key),复杂对象就是针对多个对象,存储时不同对象需要设置不同的Key

    首先看一下系统对象两种归档方式(注意由于本章主要介绍Foundation内容,下面的程序是OS X命令行程序并没有创建成iOS应用,如果移植到到iOS应用下运行将NSArchiverNSUnarchiver换成NSKeyedArchiverNSKeyedUnarchiver。虽然在Foundation部分iOSOS X在设计上尽可能通用但是还存在着细微差别。)

    //

    //  main.m

    //  FoundationFramework

    //

    //  Created by Kenshin Cui on 14-2-16.

    //  Copyright (c) 2014 Kenshin Cui. All rights reserved.

    //


    #import <Foundation/Foundation.h>


    //系统对象简单归档

    void test1(){

        //NSString归档

        NSString *str1=@"Hello,world!";

        NSString *path1=@"/Users/kenshincui/Desktop/archiver1.arc";

        if(![NSArchiver archiveRootObject:str1 toFile:path1]){

            NSLog(@"archiver failed!");

        }

        //NSString解档

        NSString *str2= [NSUnarchiver unarchiveObjectWithFile:path1];

        NSLog(@"str2=%@",str2);//结果:str2=Hello,world!

        

        

        //NSArray归档

        NSString *path2=@"/Users/kenshincui/Desktop/archiver2.arc";

        NSArray *array1=@[@"Kenshin",@"Kaoru",@"Rosa"];

        if(![NSArchiver archiveRootObject:array1 toFile:path2]){

            NSLog(@"archiver failed!");

        }

        //NSArray解档

        NSArray *array2=[NSUnarchiver unarchiveObjectWithFile:path2];

        [array2 enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {

            NSLog(@"array2[%lu]=%@",idx,obj);

        }];

        /*结果:

         array2[0]=Kenshin

         array2[1]=Kaoru

         array2[2]=Rosa

         */

    }


    //系统复杂对象归档(多对象归档)

    void test2(){

        /*归档*/

        NSString *path1=@"/Users/kenshincui/Desktop/archiver3.arc";

        

        int int1=89;

        CGSize size1={12.5,16.8};

        NSNumber *number1=@60.5;

        NSString *str1=@"Hello,world!";

        NSArray *array1=@[@"Kenshin",@"Kaoru",@"Rosa"];

        NSDictionary *dic1=@{@"name":@"Kenshin",@"age":@28,@"height":@172.5};

        

        //同时对多个对象进行归档

        NSMutableData *data1=[[NSMutableData alloc]init];//定义一个NSMutableData用于临时存放数据

        NSKeyedArchiver *archiver=[[NSKeyedArchiver alloc]initForWritingWithMutableData:data1];//定义归档对象

        [archiver encodeInt:int1 forKey:@"int"];//int1归档并指定一个key以便以后读取

        [archiver encodeSize:size1 forKey:@"size"];

        [archiver encodeObject:number1 forKey:@"number"];

        [archiver encodeObject:str1 forKey:@"string"];

        [archiver encodeObject:array1 forKey:@"array"];

        [archiver encodeObject:dic1 forKey:@"dic"];


        [archiver finishEncoding];//结束归档

        

        [data1 writeToFile:path1 atomically:YES];//写入文件

        

        

        

        /*解档*/

        int int2;

        CGSize size2;

        NSNumber *number2;

        NSString *str2;

        NSArray *array2;

        NSDictionary *dic2;

        

        NSData *data2=[[NSData alloc]initWithContentsOfFile:path1];//读出数据到NSData

        NSKeyedUnarchiver *unarchiver=[[NSKeyedUnarchiver alloc]initForReadingWithData:data2];

        

        int2= [unarchiver decodeInt64ForKey:@"int"];

        size2=[unarchiver decodeSizeForKey:@"size"];

        number2=[unarchiver decodeObjectForKey:@"number"];

        str2=[unarchiver decodeObjectForKey:@"string"];

        array2=[unarchiver decodeObjectForKey:@"array"];

        dic2=[unarchiver decodeObjectForKey:@"dic"];

        

        [unarchiver finishDecoding];

        

        NSLog(@"int2=%i,size=%@,number2=%@,str2=%@,array2=%@,dic2=%@",int2,NSStringFromSize(size2),number2,str2,array2,dic2);

        /*结果:

         int2=89,

         size={12.5, 16.800000000000001},

         number2=60.5,

         str2=Hello,world!,

         array2=(

             Kenshin,

             Kaoru,

             Rosa

         ),

         dic2={

             age = 28;

             height = "172.5";

             name = Kenshin;

         }

         */

    }



    int main(int argc,char *argv[]){


        test1();

        test2();

        

        return 0;

    }

    接下来看一下自定义的对象如何归档,上面说了如果要对自定义对象进行归档那么这个对象必须实现NSCoding协议,在这个协议中有两个方法都必须实现:

    -(void)encodeWithCoder:(NSCoder *)aCoder;通过给定的Archiver对消息接收者进行编码;

    -(id)initWithCoder:(NSCoder *)aDecoder;从一个给定的Unarchiver的数据返回一个初始化对象;

    这两个方法分别在归档和解档时调用。下面通过一个例子进行演示(注意对于自定义类的多对象归档与系统类多对象归档完全一样,代码中不再演示):

    Person.h

    //

    //  Person.h

    //  FoundationFramework

    //

    //  Created by Kenshin Cui on 14-2-16.

    //  Copyright (c) 2014 Kenshin Cui. All rights reserved.

    //


    #import <Foundation/Foundation.h>


    @interface Person : NSObject<NSCoding>


    @property (nonatomic,copy) NSString *name;

    @property (nonatomic,assign) int age;

    @property (nonatomic,assign) float height;

    @property (nonatomic,assign) NSDate *birthday;


    @end

    Person.m

    //

    //  Person.m

    //  FoundationFramework

    //

    //  Created by Kenshin Cui on 14-2-16.

    //  Copyright (c) 2014 Kenshin Cui. All rights reserved.

    //


    #import "Person.h"


    @implementation Person


    #pragma mark 解码

    -(id)initWithCoder:(NSCoder *)aDecoder{

        NSLog(@"decode...");

        if (self=[super init]) {

            self.name=[aDecoder decodeObjectForKey:@"name"];

            self.age=[aDecoder decodeInt64ForKey:@"age"];

            self.height=[aDecoder decodeFloatForKey:@"heiht"];

            self.birthday=[aDecoder decodeObjectForKey:@"birthday"];

        }

        return self;

    }


    #pragma mark 编码

    -(void)encodeWithCoder:(NSCoder *)aCoder{

        NSLog(@"encode...");

        [aCoder encodeObject:_name forKey:@"name"];

        [aCoder encodeInt64:_age forKey:@"age" ];

        [aCoder encodeFloat:_height forKey:@"height"];

        [aCoder encodeObject:_birthday forKey:@"birthday"];


    }


    #pragma mark 重写描述

    -(NSString *)description{

        NSDateFormatter *formater1=[[NSDateFormatter alloc]init];

        formater1.dateFormat=@"yyyy-MM-dd";

        return [NSString stringWithFormat:@"name=%@,age=%i,height=%.2f,birthday=%@",_name,_age,_height,[formater1 stringFromDate:_birthday]];

    }


    @end

    main.m

    //

    //  main.m

    //  FoundationFramework

    //

    //  Created by Kenshin Cui on 14-2-16.

    //  Copyright (c) 2014 Kenshin Cui. All rights reserved.

    //


    #import <Foundation/Foundation.h>

    #import "Person.h"



    int main(int argc,char *argv[]){


        //归档

        Person *person1=[[Person alloc]init];

        person1.name=@"Kenshin";

        person1.age=28;

        person1.height=1.72;

        NSDateFormatter *formater1=[[NSDateFormatter alloc]init];

        formater1.dateFormat=@"yyyy-MM-dd";

        person1.birthday=[formater1 dateFromString:@"1986-08-08"];

        

        NSString *path1=@"/Users/kenshincui/Desktop/person1.arc";

        

        [NSKeyedArchiver archiveRootObject:person1 toFile:path1];


        //解档

        Person *person2= [NSKeyedUnarchiver unarchiveObjectWithFile:path1];

        NSLog(@"%@",person2);

        /*结果:

         name=Kenshin,age=28,height=0.00,birthday=1986-08-08

         */

        

        return 0;

    }

    展开全文
  • 1.Foundation概述

    2015-01-23 15:52:12
    为什么前面说的内容中新建一个类的时候我们都是选择Cocoa Class呢?Cocoa是什么呢? Cocoa不是一种编程语言(它可以运行多种编程语言),它也不是一个开发工具(通过命令行我们仍然可以开发Cocoa程序),它是创建...

    为什么前面说的内容中新建一个类的时候我们都是选择Cocoa Class呢?Cocoa是什么呢?

    Cocoa不是一种编程语言(它可以运行多种编程语言),它也不是一个开发工具(通过命令行我们仍然可以开发Cocoa程序),它是创建Mac OS X和IOS程序的原生面向对象API,为这两者应用提供了编程环境。

    我们通常称为“Cocoa框架”,事实上Cocoa本身是一个框架的集合,它包含了众多子框架,其中最重要的要数“Foundation”和“UIKit”。前者是框架的基础,和界面无关,其中包含了大量常用的API;后者是基础的UI类库,以后我们在IOS开发中会经常用到。这两个框架在系统中的位置如下图:

    Cocoa

    其实所有的Mac OS X和IOS程序都是由大量的对象构成,而这些对象的根对象都是NSObject,NSObject就处在Foundation框架之中,具体的类结构如下:

    Foundation1

    Foundation2

    Foundation3

    通常我们会将他们分为几类:

      1. 值对象
      2. 集合
      3. 操作系统服务:文件系统、URL、进程通讯
      4. 通知
      5. 归档和序列化
      6. 表达式和条件判断
      7. Objective-C语言服务

    UIKit主要用于界面构架,这里我们不妨也看一下它的类结构:

    UIKit

    展开全文
  • foundationdb

    2018-04-23 22:21:00
    苹果公司宣布将分布式nosql数据库foundationdb 开源。历史2009年, 由 Nick Lavezzo, Dave Rosenthal, and Dave Scherer创立;2015年3月,由苹果公司收购;2018年4月,苹果公司宣布foundationdb开源。...
    苹果公司宣布将分布式nosql数据库foundationdb 开源。


    历史
    2009年, 由 Nick Lavezzo, Dave Rosenthal, and Dave Scherer创立;2015年3月,由苹果公司收购;2018年4月,苹果公司宣布foundationdb开源。

    设计限值
    The design of FoundationDB results in several limitations:
    Long transactions
    FoundationDB does not support transactions running over five seconds.
    Large transactions
    Transaction size cannot exceed 10 MB of total written keys and values.
    Large keys and values
    Keys cannot exceed 10 kB in size. Values cannot exceed 100 kB in size.

    开源地址

    foundationdb 网站提供的下载地址

    db排名
    DB-Engines网站上未有对该数据库的排名。

    编程语言
    c++

    架构图

    源码安装步骤
    linux下源码安装步骤待补充





    展开全文
  • 框架:AngularJS、Foundation,构建工具:Gulp,开发环境:node.js。操作系统:Mac相关链接:foundation: http://foundation.zurb.com/gulp:http://gulpjs.com/1. 环境准备(1) 安装node.js:在 ...
  • 一、Foundation框架—错误接收与异常处理  我们都知道程序在运行过程中难免会出现各种错误和特殊问题,这个时候就需要我们使用接受错误(error)和捕获异常(Exception)。 1. 错误接收:  1). 在C语言中常常会...
  • SCPPO(六):源代码管理工具---Team Foundation Server

    万次阅读 热门讨论 2019-08-01 10:18:30
    细细数来在这个项目开发过程中,也用到很多工具哎,项目管理软件—Worktitle、源代码管理工具—Team Foundation Server、开发工具—VS2013、SQLServer2012! 自己参与的这个项目主要工作是维护,前辈们已...
  • TFS(Team Foundation Server)介绍和入门

    万次阅读 2008-10-22 10:10:00
    在本文的两个部分中,我将介绍Team Foundation Server的一些核心特征,重点介绍在本产品的日常应用中是如何将这些特性结合在一起使用的。作为一名软件开发人员,在我的职业生涯中,我经常会用到支持软件开发过程的...
  • [Addison-Wesley Professional] Essential Windows Workflow Foundation [Microsoft Press] Microsoft Windows Workflow Foundation Step by Step [Packt Publishing] Programming Windows Workflow Foundation ...
  • ARFoundation之路-图像跟踪

    千次阅读 热门讨论 2019-08-15 16:38:44
      图像跟踪技术,是指通过图像处理技术对摄像头中拍摄到的2D图像进行定位,并对其姿态进行跟踪的技术。图像跟踪技术的基础是图像识别,图像识别是指识别和检测出数字图像...  在ARFoundation中,图像跟踪系统依...
  • 本资源为《Windows Presentation Foundation程序设计指南》的中文全本高清扫描Pdf,并附带原书所有章节源代码。该书原作者:Charles Petzold,译者:蔡学镛 《Windows Presentation Foundation程序设计指南》主要...
  • ARFoundation之路-平面管理

    千次阅读 2019-07-09 09:56:07
    同时,平面也是可跟踪对象,在前几节中我们知道,ARFoundation使用ARPlaneManager管理器来管理平面。 (一)平面检测管理   AR中检测平面的原理:ARFoundation对摄像机获取的图像进行处理,分离图像中的特征点...
  • ARFoundation已支持LWRP

    千次阅读 2019-01-28 10:30:12
    虽然现在做网游,对以前做的AR始终念念不忘,今天看到了ARFoundation对LWRP的支持,意味着可以使用最新的轻量级渲染管线进行AR开发。 随着不断的发展,AR Foundation也支持了轻量级渲染管线LWRP,这意味着开发者...
  • ios Core Foundation 框架 详解

    千次阅读 2018-09-07 14:55:11
    先来说说「Core Foundation」(以下简称CF)的历史吧。当年乔布斯被自己创办的公司驱逐后,成立了「NeXT Computer」,其实做的还是老本行:卖电脑,但依旧不景气。好在NeXTSTEP系统表现还不错,亏损不至于太严重。...
  • Asimov, Isaac - Foundation 1 - Prelude to Foundation.txt Asimov, Isaac - Foundation 2 - Forward the Foundation.txt Asimov, Isaac - Foundation 3 - Foundation.txt Asimov, Isaac - Foundation 4 - ...
  • 前端进阶,从Foundation UI框架开始

    千次阅读 2017-09-19 07:21:01
    我不是第一个吃螃蟹的人 最近这些年,前端很火... Foundation能做什么 还记得很多年前,有一个贵妇人问过法拉第:“先生,您发现的电磁感应有什么用呢?”法拉第这样回到:“女士,你知道刚生下来的孩子有什么用吗?”
  •   各位读者,经过七个月的创作,《ARFoundation之路-AR开发从入门到实践》已完成85%的内容。本书充分借鉴了《ARCore之路-Unity开发从入门到实践》在内容编排与写作上的经验教训,更加注重对技术的实际运用,力图...
  • ARFoundation之路-点云与参考点

    千次阅读 2019-07-21 09:24:16
      AR 是对现实环境的增强,运动跟踪可以解决用户在现实环境中自己在哪里的问题,但运动跟踪本身并不能解决用户周边环境是什么的问题,运动跟踪不能识别出平面,也不能...  特征点是指 ARFoundation 通过 VIO 检...
  • Professional Team Foundation Server 2010
  • Foundation框架与Core Foundation框架相互之间的桥接,有三种(可以在官方文档中搜Toll-Free Bridged Types) 第一种非ARC(MRC)情况下,直接强制转换(不用桥接)Foundation框架->Core Foundation框架 Core ...
1 2 3 4 5 ... 20
收藏数 233,986
精华内容 93,594
关键字:

foundation