#import <Foundation/Foundation.h>
#import "Person.h"

int main(int argc, const char * argv[]) {
#pragma mark -----------------------OC类和对象---------------------------------------------------
    /*
1 OC-C
Objective -- C 简称OC,OC是C语言的扩充,并且OC是iOS和OS X操作系统的编程语言
OC是c语言的超集,简单来说就是,OC全面包容C语言,也就是在OC中,可以使用C语言代码,编译器可以兼容C语言,并对其进行编译,执行。
具备完善的面向对象特性。封装,继承,多态。
包含一个运行时系统;
类库丰富
OC 和Swift背后的思想以及所托的类库都是相同的
面向对象的核心思想是类和对象
     
2 面向过程 和 面向对象
2.1 面向过程   po  : Procedure Oriented
面向过程 :以事情为中心,考虑完成下项目所需的步骤,在整体步骤确定之后,每个步骤之间都是有联系的,环环相扣。
优点 : 所产生的代码,比较稳定。
缺点 : 重用性不高。不够灵活,当根据改进条件,需要改变某一步骤时,就会改动整个程序,相当于重写程序。

2.2 面向对象   OOP:Object Oriented Pragramming
面向对象 :以事物为中心,考虑完成项目需要的对象,完成一个项目需要很多对象,这些对象有自己的功能和特性(像有生命一样,可以自己完成你交代的事情),彼此之间没有联系,当需要的时候,可以调用(命令)他们完成事情。
特点 : 不比面向过程稳定,但是比面向过程灵活。
向对象具有良好的可扩展性和重用性。
向对象可以降低我们代码的耦合度,提 代码的可移植性。
向对象接近于日常生活和自然的思考方式,可以提我们软件开发的效率和质量
2.3 面向过程与面向对象 的区别与联系
     特点
     PO :分析解决问题的步骤,实现函数,依次调用函数
     OOP :分析该问题需要参与的对象,各个对象的作用,完成该事件需要多个对象那个协同完成该任务
     侧重点
     PO :实现功能(步骤)
     OOP:对象的设计(包含哪些特征和行为)
     
3 类 和 对象
3.1类是具有相同特征和行为的事物的抽象。
把具有相同 特征 和 行为 的东西,放在一个集合里面,取名叫做类型。
3.2 对象是一个类的具体体现。
3.3 类和对象的关系
     类是对象的类型(与int、float类似);对象是一个类的实例,是一个类型里面的一个事物(对象)
     

   */
#pragma mark-----------------------OC初始化方法---------------------------------------------------
    /*
1.类的创建
     OC中类的定义分为两个部分:接口部分和实现部分
     接口部分 :对外声明类的特征和行为。(.h文件中)
     实现部分 :   行为的具体体现,(.m文件中)
1.1   .h 文件                 接口部分标志 : @interface...@end
1)@interface...@end 的作业 :声明类的实例变量(成员变量)和方法,既类的特征和行为
2)接口部分包含的内容 : 类名、父类名、实例变量声明、方法声明等
3)接口代码  
     
a    //引入框架
#import <Founddation/Foundation.h>
  在每一个声明文件开始时,都要引入这个类库
     
b    //     接口部分标志
@interface  类名 : 父类名(NSObject)

c  //     实例变量声明
{
        类型修饰符 *实例变量  ;
     
}
******************************
     在OC中,用了nextStep这个语言的前缀 NS 来标记各种类型。在OC中
基本类型来定义实例变量,不用加 * 号,(int,float,NSinteger等)
不是基本类型的才用加上 * 号。(NSNumber,NSString等)
     
     类名命名规范  : 类名首字符要     大写
     实例变量命名  :实例变量前要加下划线 _
 ***********    ******************
     
d   //     方法声明
调用方法  (返回值类型)方法名 ;
     
e   // @end  表示接口的结束
     
1.2    .m 文件                    实现部分标志  :@implementation...@end  的作用 : 类行为的具体实现(方法的实现)
     
1) 实现代码
     
 a   //在实现文件里的第一件事,就是好将这个类的头文件引过来。这样才能识别这个类。
#import "l类名 . h"
     
b    //@implemention表示实现的开始,后面跟着    类名  表示要实现这个  类
@implemention 类名
     
c    //实现方法
 调用方法  (返回值类型)方法名
{
        方法实现过程;
}
d   //@end 表示实现部分的结束
     
1.3   main.m 文件   调用方法
1) #@import  "类名 .h"
     
在main 函数中 代码
2)在 OC 中 ,[   ] 表示调用 方法 ,形式为[类名  方法名],或者 [对象名 + 方法名]     有两种方法
  a 类方法:与实例方法相反 ,用 + 号在前标识 。 +(void)方法名;
  b 对象方法(实例方法): 用 - 号在前标识。        - (void)方法名;
     
3)使用对象
     OC中使用对象 :
     对象名 --->实例变量。 如person->_name = 20;   NSLog(@"%ld",person->_name);
     
1.4    输出 NSLog
     与C语言的printf 用法一样,OC中,在每一个字符串前,都要加上 @  。
     格式  NSLog(@"内容  占位符" ,对应的实例变量既对象);
NSString 输出格式占位符 为     %@
     
2 继承
面向对象的三大特性:封装,继承,多态。
继承特性:
》》 把公共的方法和实例变量写在父类 , 子类只需要写自己独有的实例变量和方 即可。继承既能保证类的完整, 能简化代码。
》》没有父类的类称为根类,
》》OC中的根类是NSObjec (祖宗)。
》》继承的上层: 父类,继承的下层:子 类。
》》继承的内容:所有实例变量和方法。 继承是单向的,不能相互继承。
》》继承具有传递性:A继承于B,B继承于C,A具有B和C的特征和行为。
》》如果子类不满意父类方法的实现,可以重写(overwrite) 父类的方法
重写从 类继承过来的 法的三种情况:
完全以 类的实现内容为主,丢弃 类实现的内容。
完全以 类的实现内容为主,没有 类实现的内容。
 既有 类对该 法的实现,也有 类对该 法的实现。
《《在OC中使用消息发送机制:[receive message]  
》》如果向super发送消息,一级一级向上找,最后在根类(NSObject)中也没找到,程序会Crash
     
3 super  /    self    / id  instancetype       /加号方法  减号方法
3.1 super
》》》super 是编译器指令,并非对象
》》作用:给super发消息,可以执行父类该方法的实现

3.2 self
self是系统关键字。  self在方法中指代当前方法的调用者
self在实例方法中,指代调用当前方法的对象
self在类方法中,指代当前类。
     
3.3 id/instancetype
instancetype 可以返回和方法所在类相同类型的对象。
id只能返回未知类型的对象
instancetype只能作为返回值和参数,
id还可以用来定义变量
instancetype会告诉编译器当前的类型,
id对于编译器却是无类型的,调用任何方法都不会给出错误提示
对于init方法,id和instancetype是没有区别的,因为编译器会把id优化成instancetype。当明确返回的类型就是当前Class时,使用instancetype能避免id带来的编译不出的错误情况
    

     
3.4 OC中的方法
在 OC 中 ,[   ] 表示调用 方法 ,形式为[类名  方法名],或者 [对象名 + 方法名]     有两种方法
     a 类方法:与实例方法相反 ,用 + 号在前标识 。 +(void)方法名;   只能被类使用
     b 对象方法(实例方法): 用 - 号在前标识。        - (void)方法名;   只能对象使用
     
方法名 :类型标识  返回值类型  参数类型  参数名 空格
类中不能出现同名方法
冒号 : 标识参数,不能省略。有冒号必须有参数
冒号属于方法名的一部分
     
     *************************************
     调用方法是 :
-(void)replaceObjectAtIndex :(NSUinteger)index  withObject :(id)anObject
-   方法标识符
     (void)返回值类型
replaceObjectAtIndex      withObject    参数形容词(参数名)
(NSUinteger) (id)   参数类型  
index     anObject   参数名
**************************************************
     
在OC中使用消息发送机制:[receive message]
     Teacher *teacher = [[Teacher alloc] init];
     [teacher getSalary];
正确表述:给teache 对象发送getSalary消息。 teache 接收到消息,即方法getSalary。 teache 找到getSalary 法,并执行。

3.5  new 和alloc/init
     
     
4 创建对象---------初始化方式  (3种)
创建对象分两步:
//分配内存空间 :根据类中声明的实例变量为对象在堆区分配内存,并返回首地址。并且将内存空间数据清零
     Teacher *teacher =[Teacher alloc];
     
//  初始化 :为对象的实例变量设置初始值
     teacher = [teacher init];

l两步是一个连续的过程,一般情况下,合并操作
     Teacher *teacher =[[Teacher alloc]init];

*** alloc  分配内存,空间
*** init 初始化
     
开辟空间     +(instancetype)alloc ;
+ 号方法 既 类方法,只能由类调用。 instancetype 返回值类型 可以用(id)任意对象类型替代

初始化         -(istancetype)init ;  对象方法,对象调用
     
1)系统方法
******指针存储对象的首地址,代指对象。OC中使用指针代指对象,进行操作。
如Student *student  ->(_name  _gender  _age)
student(对象名)存储  首地址 ,代指对象
真正的对象是 特征 既实例变量(_name _gender _age)
对象存储在  堆区
***************************************
类名 *对象名 = [[类名 alloc] init] ;

+++++++++++++++++++++++++++++
     .h文件      声明
-(instancetype)init;
     
     .m文件     实现
-(instancetype)init;
{
        self = [super init] ;
》》》给super发送init消息 :执行父类中实现的init 方法
     
        if (self){
》》》判断从父类继承过来的init方法是否初始化成功
     
》》》初始化设置_name = 赋值;
     }
     return self;
》》》返回初始化完成的对象
     
}
     main.m文件    调用
Person person = [[Person alloc]init]
     
++++++++++++++++++++++++++++++++++
在自身的初始化方法中,优先向super发送init 消息,初始化公共变量, 初始化成功之后,再初始化自身特有变量,从而完成全部实例变量的初 始化。
     
2)自定义方法
》》一个类可以有多个初始化方法。 虽然可以有多个初始化方法,但是一个对象只能使 一个初始化方法
+++++++++++++++++++++++++++++++++++++
     .h文件      声明
-(instancetype)initWith实例变量 :(类型修饰符)实例变量及参数(无下划线);
     
     .m文件     实现
-(instancetype)initWith实例变量:(类型修饰符)实例变量及参数(无下划线);
{
self = [super init] ;
》》》给super发送init消息 :执行父类中实现的init 方法
     
if (self){
》》》判断从父类继承过来的init方法是否初始化成功
     
》》》初始化设置_name = name;
//     name就是参数
}
return self;
》》》返回初始化完成的对象
     
}
     
 main.m文件    调用
Person person = [[Person alloc]initWith实例变量:赋值]
 ++++++++++++++++++++++++++++++++++++++
    
3) 便利构造器
》》 封装了对象创建过程:
》》内部实现:封装了alloc和初始化操作,创建对象更加方 便 快捷。
》》》便利构造器是“+” 法     返回 本类型 的实例    方法名以类名开头    可以有0到多个参数。
+++++++++++++++++++++++++++++++++++++++++
     .h 文件   声明
+(类名)类名With实例变量 :(类型修饰符)实例变量既参数(无下划线);
     
     .m 文件  实现
+(类名)类名With实例变量 :(类型修饰符)实例变量及参数(无下划线)
     {
        类名 *对象名 = [[类名  alloc]initWith实例变量 :实例变量既参数];
     return  self ;
     }
     
     main.m 文件中
     调用   类名 *对象名 = [[类名  alloc]initWith实例变量 :赋值];
 ++++++++++++++++++++++++++++++++++++++++++++++
//    冒号后的实例变量就和   函数中的参数一样 ,可以随便赋值。
//    init后面的实例变量可以省略下划线
     

     
************************************
》》》初始化 法的主要作 是:为某些实例变量赋初值。
》》》初始化 法在对象的整个生命周期只使用一次。
注:初始化 法是在对象的初始化阶段完成其实例变量的值操作, 个对象的初始化阶段只有一次,所以初始化方法
只使 一次。
》》1. 自己  的初始化 方法中,优先调 用 类的初始化 方法。
》》2. 类的初始化方法中再调 用父 类的初始化 方法,依次往上调 。
》》3.处于最上层的初始化完成之后,回到第 二层的初始化方 法中, 完 成第二 层的初始化。
》》4. 第 层的初始化完成之后,回到第三层的初始化方法中,依次执行 初始化方法,直到本类的初始化 方法完成
***********************************
     */
#pragma mark-----------------------OC属性和点语法-------------------------------------------------
    /*
1   setter 和 getter 方法
在OC ,为单一实例变量赋值的方法称作 setter  (设置器)
             获取单一实例变量值的方法称作getter (访问器)。
setter 和getter方法访问的是单一实例变量
setter 和 getter 内部操作的是实例变量。 每 个实例变量都需要一对setter 和getter法
1.1setter
     .h 文件
- (void)setAge:(NSInteger)age;    -(返回值类型)set实例变量:(类型修饰符)实例变量既参数
即set+ 首字母大写的实例变量名(忽略下划线)。
     
     .m 文件
- (void)setAge:(NSInteger)age;    -(返回值类型)set实例变量:(类型修饰符)实例变量既参数
{
        实例变量  = 参数;
        _name = name;
}
 
1.2 getter
     .h 文件
- (NSInteger)age;                             -  (返回值类型)方法名->实例变量相同
即返回值类型与变量类型一致, 方法名与实例变量名相同(忽略下划线)
     
     .m 文件
- (NSInteger)age;                             -  (返回值类型)方法名->实例变量相同
{
        return _name;
//返回实例变量;
}
     
2   属性
属性是Objective-C 2.0 定义的语法,提供setter 、getter 法的默认实现。在一定程度上简化程序代码,并且提 高程序的安全性。
2.1 代码
****************************************************
     .h 文件  声明
@propertry NSString  *name;
//   @propertry  类名  *实例变量;
//     相当于在@interface声明了两个方法
     
     .m 文件  实现
@synthesize  name = _name;
//     (@synthesize  实例变量)    实现声明的属性
//     指定生成的setter 和 getter方法内部操作的实例变量
//      相当于在@implementation实现了两个方法
*****************************************************
属性的作用是生成setter以及getter方法的实现,如果方法内部操作的实例变量未定义,系统会自动生成一个 _属性名的实例变量,但是生成的实例变量的可见度是私有的,子类不可访问。
一旦同时重写了 setter、setter方法,并且没有实现   @synthesize就不再生成实例变量
   
2.2 属性的特点
关键字既属性的特性
1)读写性控制(readonly、readwrite、setter=、getter=)
readonly :只读状态,是告诉编译器,属性只生成getter方法,不生成setter方法
readwrite : 读写状态,是告诉编译器,属性既生成setter方法又生成getter方法,既有设置器,也有访问器,默认的读写特性。
setter= : 指定属性生成的setter方法的名字。
getter= :指定属性生成的getter方法的名字。

2)原子性控制(nonatomic,atomic)
atomic:原子特性, setter 、getter方法在多线程访问下是绝对安全的,即setter、getter内部做了多线程访问处理。默认的原子特性。
 nonatomic: 非原子特性。 setter 、getter方法内部不会做多线程访问处理,仅仅是普通的 setter、getter方法。
 
程序开发过程中, setter、getter会频繁使用 ,如果使用atomic需要不断的对setter、getter加锁解锁以保证线程访问的安全,会非常占用系统资源,降低系统性能。
声明属性时,通常使用nonatomic。某些属性需要线性安全的时候,才会定义为atomic
     
3)语义设置(assign 、retain、copy)
如果属性是非对象类型(int、float等)属性的语义设置时,用 assign
如果属性是对象类型(NSString等)属性的语义设置使用retain
如果属性是对象类型并且想得到对象的副本,使用copy。
*********************************************
     retain的内部实现
    -(void)setName :(NSString *)name
     {
        if(_name != name){
            [_name relaese];
            _name = [name retain];
        }
     }
     ********
     -(NSString *)name{
     return [[_name retain]autorelease];
     
     }
********************************************
********************************************
  retain的内部实现
     -(void)setName :(NSString *)name
     {
        if(_name != name){
        [_name relaese];
        _name = [name  copy];
            }
     }
     ********
     -(NSString *)name{
     return [[_name retain]autorelease];
     
     }
********************************************
     
3 点语法
Objective-C 2.0 中定义的语法格式。提供了一种便捷的属性访问方式
只要符合系统默认setter、getter书写格式的方法都可以使用点语法
属性是一对getter、setter方法,点语法是属性的另一种调用格式
[person setName : @"SB"];
person.name = @"SS";
注意 : 点语法点的属性名、

4  可见度
OC的实例变量可见度有四种 : @package,@public,@protected,@private。
package比较少用。
类内 :在类接口和实现以内
类外 : 在类接口和实现之外
在类外如果想直接使用实例变量,必须使用@public来修饰可见度,否则不能直接操作实例变量
1)@public
在类内和类外都可以直接使用,并且可以被继承。虽然这样的可见度,对我们来说很方便,但是对程序内部细节的保护没有一点帮助,因此,@public最好不用。
     
2)@protected
如果在声明成员变量的时候,没有对其使用可见度描述,则这些实例变量的默认可见度是protected的。
     protected,在类外不能使用,在类内可以使用,可以被继承(这是与private的区别)。
     
3) @private
私有可见度,描述的实例变量,在类内可以使用,在类外不能使用,并且不能被继承。
    

     */
#pragma mark-------------------------------OC对象------------------------------------------------
    
#pragma mark--------------------1 OC对象 NSString、NSNumber和NSValue-----------------------------
   /*
1 API :苹果帮助文档
   苹果每次iOS版本的升级,都会添加或更新大量API,并提供相应的 参考文献
   学会使用 API 是开发者的一项技能
1.1 打开帮助文档
   Xcode->Help->Documentation and API reference
1.2 文档基本信息
Inherits from 继承关系
Conforms to 遵循什么协议
Framework 属于哪个框架
Availability 什么时候可用
Declared in 申明在什么头文件里
Related documents 相关文档
Sample code示例代码
1.3 快捷键
   鼠标在 类名 或者 方法名 上, command + 鼠标左键
   鼠标在 类名 或者 方法名 上 ,option(alt)+ 鼠标左键
1.4 API和头文件的区别
API 中详细的介绍了方法的作用以及如何使用(可以查看类的功能)
头文件内只是简单的显示方法(查看属性和方法名)
 
2 NSString
C语言中,字符串是由 char(ASCII码)字符组成
OC中,字符串是由 unichar(Unicode)字符组成
NSString :不可变字符串,既:创建以后,内容和长度不能更改
NSMutablestring : 可变字符串,既 :创建以后,内容还可以修改
   
2.1 字符串创建 初始化方法:
1)  NSString *str1 = [[NSString alloc]initWithFormat : @"I love iOS"];
//initWithUTF8String : 作用将C语言的字符转化为 OC 的字符串对象
NSString *str2 = [[NSString alloc]initWithUTF8String:C语言字符];
   
format------------格式串(使用方式和C语言格式化输出函数 printf相似)
2) 便利构造器
   
NSString *str3 = [NSString stringWithFormat : @"I love iOS"]
// 可以传入多个字符串(不受限制)
NSString *stu4 = [NSString stringWithUTF8String:b];
//只能传一个字符串
   //    如果参数是一个字符串对象,现将字符串中的值拷呗到堆区,然后再返回堆区地址
   //    如果参数是一个常量字符串,直接返回常量区地址
   
3)字面量 (语法糖):赋值方便快捷,但功能单一,缺少灵活性。和new相似
   NSString *Str5 = @"I love IOS!" ;
   
2.2 NSString操作函数
1)获取字符串长度     [字符串名 length]     字符串名 . length
    NSString *stu3 = @"ipad";
    NSLog(@"%ld",stu3.length);
    
2) 获取字符串中的字符      characterAtIndex
    char a[10] = "ipad";
    NSString *stu3 = [NSString stringWithUTF8String:a];
    unichar stu4 = [stu3 characterAtIndex:1];
    NSLog(@"%c",stu4);
    
3) 获取子字符串的方法 ubstringFromIndex
//    重指定位置开始,直到字符串结束
    NSString *stu6 = [stu5 substringFromIndex:0];
    NSLog(@"%@",stu6);
    
4) 从开头到指定位置结束 substringToIndex
    NSString *stu7 = [stu5 substringToIndex:1];
    NSLog(@"%@",stu7);
    
5) 控制开头和结尾
//    定义一个结构体变量(OC中的结构体 NSRange)
//    location控制开始的位置  length控制结尾
//    第一个数是位置
//    第二个数是长度
    NSRange range = NSMakeRange(1, 3);
    NSString *str = [str3 substringWithRange:range];
    NSLog(@"%@",str);
   
6)指定范围   NSMakeRange(a,b);
     NSRange range = NSMakeRange(1, 3);
   
7) 字符串拼接的方法  stringByAppendingString
   NSString *str1 = [NSString stringWithFormat:@"你好,我是谁?"];
   NSString *stu1 = [str1 stringByAppendingString:@"你好,我不知道!"];
   NSLog(@"%@",stu1);
    
8)  替换字符串  stringByReplacingOccurrencesOfString
//    string : 替换主体。也就是被替换者
//    第一个参数 :被替换者的局部字符串(可以是全部)
//    注意 ; 必须是替换主体自身原本拥有的字符串,才可以被替换
//    第二个参数:替换的新成员
    NSString *string = @"hello,美女!";
    NSString *string0 = [string stringByReplacingOccurrencesOfString:@"hello" withString:@"你好"];
    NSLog(@"%@",string0);

9)  判断两个字符串是否相等的方法     isEqualToString
//(判断字符串的内容中的大小写,长度是否一致)
    NSString *str = @"123";
    NSString *stu = @"023";
    NSLog(@"%d",[str isEqualToString:stu]);
    
10)判断获取的字符串前缀   hasPrefix
    if ([stu hasPrefix:@"0"]) {
        NSLog(@"大猪头");
    }
    
11)    判断后缀      hasSuffix
    if ([str hasSuffix:@".jpg"]) {
        NSLog(@"小猪头");
    }
   
12)  大小写转换
     全部大写 : uppercaseString
     全部小写 : lowwercaseString
     首字母大写:capitalizedstring
   
    NSString *s2 = @"I love Mac";
    1 全部大写
    NSString *s3 = [s2 uppercaseString];
    NSLog(@"%@",s3);
    2 全部小写
    NSString *s4 = [s2 lowercaseString];
    NSLog(@"%@",s4);
     3 首字母大写
    NSString *s5 = [s2 capitalizedString];
    NSLog(@"%@",s5);
    
13)查找某个字符串在另一个字符串的范围 :   rangeOfString
14)字符串比较(大小 unicode)  compare :
15)字符串和数值的类型转换 : intValue
    
2 不可变字符串  NSMutableString
//1 NSString 改的是副本
//  NSMutableString 改的是自身
// NSString 是父类,NSMutableString是它的子类,继承与它
// 父类有的方法子类可以继承,同时子类也有自己独特的方法
   
2.1初始化创建  3种方法
   
1) 初始化方法:
   NSMutableString *str1 = [[NSMUtablestring alloc]initWithFormat : @"I love iOS"];
   
   NSString *str2 = [[NSString alloc]initWithUTF8String:C语言字符];
   
   //initWithUTF8String : 作用将C语言的字符转化为 OC 的字符串对象
   format------------格式串(使用方式和C语言格式化输出函数 printf相似)
   
2) 便利构造器
   NSMutableString *str3 = [NSMutableString stringWithFormat : @"I love iOS"]
// 可以传入多个字符串(不受限制)
   NSMutableString *stu4 = [NSMutableString stringWithUTF8String:b];
//只能传一个字符串
//    如果参数是一个字符串对象,现将字符串中的值拷呗到堆区,然后再返回堆区地址
//    如果参数是一个常量字符串,直接返回常量区地址
   
3)字面量 (语法糖)
   NSMutableString *Str5 = [@"I love IOS!" ]mutablecopy;
   NSMutableString *mutable1 = @"1234.png".mutableCopy;
//    字面量赋值在对可变字符串时需要加mutableCopy
   
    NSMutableString *mutable = [NSMutableString stringWithString:@"12345"];
    NSLog(@"%@",mutable);

2.2 可变字符串操作函数
1) 可变字符串的拼接
    [mutable appendString:@"54321"];
    NSLog(@"mutable = %@",mutable);
//   可变字符串的插入
//    第一个参数的类型是字符串,插入的内容
//    第二个参数是无符号长整形,插入的位置
//    [mutable insertString:@"abcd" atIndex:6];
//    NSLog(@"%@",mutable);
//    可变字符的删除
 //    NSRange ra = NSMakeRange(6, 4);
//    [mutable deleteCharactersInRange:ra];
//    NSLog(@"%@",mutable);
    
2) 替换字符串
    [mutable replaceCharactersInRange:NSMakeRange(2, 4) withString:@"@%$^"];
    NSLog(@"%@",mutable);
    
3)重置字符串
    [mutable setString:@"6666666666"];
    NSLog(@"%@",mutable);
   
4)    替换Range(a,b)
 //    从a个元素开始,到a后面的b个元素
   
5) 插入字符串 :insertString : atIndex :
    

三   NSNumber (数值类)
   作用:实现      基本数据类型   与     OC对象类型  的相互转化
   基本数据类型(int,float等)转化为 NSnumber
   NSNumber 转化为基本数据类型(int,float等)
   
1. NSNumber 类型声明三种方法
   1)系统初始化       initWithint
   2)便利构造器       numberWithinteger
   3)字面量              @数值
   常量 : NSNumber *intNUmber = @38;
                 NSNumber *charNumber =@'w';
   变量 :
   int number = 18;
    NSNumber *num = @(number);
    NSLog(@"%@",num);
   
2.基本数据类型 转换为 对象   numberWithChar
2.1  char     + (NSNumber *)numberWithFloat:(float)value;
    char number = 'w';
    NSNumber *number1 = [NSNumber numberWithChar:number];
   
   2.2    int   + (NSNumber *)numberWithInt:(int)value;
    int a = 10;
    NSNumber *num2 = [NSNumber numberWithInt:a];
    NSNumber *num2 = @(a);
    NSLog(@"%@",num2);

2.3   double
   double b = 43.2;
   NSNumber *num3 = [NSNumber numberWithDouble:b];
    NSNumber *num3 = @(b);
    NSLog(@"%@",num3);

2.4   BOOL
    BOOL c = 1;
    NSNumber *num4 = [NSNumber numberWithBool:c];
    NSNumber *num4 = @(c);
    NSLog(@"%@",num4);
    
    
3 将对象转化成基本类型数据    intvalue
3.1  int    @property (readonly) int intValue;
    NSNumber *n1 = @(20);
    int t = [n1 intValue];
    NSLog(@"%d",t);
   
3..2 char   @property (readonly) float floatValue;
   NSNumber *n2 = @('g');
   NSLog(@"%c",[n2 charValue]);
   
3.2  BOOL
    NSNumber *n3 = @('1');
    NSLog(@"%d",[n3 boolValue]);

3.3  float
    NSNumber *n4 = @(1.2);
    NSLog(@"%.2f",[n4 floatValue]);

3.4 double
    NSNumber *n5 = @(2.3);
    NSLog(@"%f",[n5 doubleValue]);
   
4 NSNumber 类型对象的比较
  - (NSComparisonResult)compare:(NSNumber *)otherNumber;
   
四NSValue :数值类,将指针结构体等类型转化为对象
   完成  结构体 、指针 和 对象类型  的 互转
   结构体(NSRange等)转换为 NSValue
   NSValue 转换为结构体(NSRange等)

1  指针和 NSValue 类型对象的转换
1)指针   ->  NSValue
    int a = 10;
    int *p = &a;
   NSValue *value = [NSValue valueWithPointer:p];
   NSLog(@"%@",value);

2) NSValue -> 指针
    int *newP = [value pointerValue];
    NSLog(@"%d",*newP);
   
2    NSRange和 NSValue 类型对象的转换          + (NSValue *)valueWithRange:(NSRange)range;
1)NSRang -> NSValue  
   NSRange range = {13,15};
    NSValue *v = [NSValue valueWithRange:range];
    NSLog(@"%@",v);

2)NSValue -->  NSRange      @property (readonly) NSRange rangeValue;
   
   *****
   + (NSValue *)valueWithRange:(NSRange)range;
   NSPoint    NSRect    NSSize  CGSize  CGPoint      CGRect  结构体类型转化为 NSValue   类型的对象
   使用方法和NSRange 一样
   
   注 : CGSize  CGPoint   CGRect  是UI中使用的结构体类型
   
   
   *****
   
3 结构体 与 NSValue  转换
   定义一个Student结构体变量 (年龄,姓名,性别)
   Student student = {"kongkong",'f',500};
1)结构体-> NSValue
   NSValue *stuValue = [NSValue valueWithBytes:&student objCType:@encode(Student)];
   NSLog(@"%@",studentValue);
///    将自定义的结构体变量转化
///    第一个参数 :结构体变量的地址
///    第二个参数 :结构体变量的类型
   
2)   NSValue --> 结构体
    Student newStu ={0};
    [stuValue getValue:&newStu];
    NSLog(@"%s %c %d",newStu.name,newStu.gender,newStu.age);
  ******
   ******
  总结
1 .可变对象通常是不可变对象的子类,包含父类所有方法,并且具有对原有对象的增、删、改功能。
   注:不可变字符串的修改方法有返回值。
        可变字符串的修改方法没有返回值。
2.可变对象的增、删、改都是对自身对象的操作。不可变对象的增、 删、改都会生成新的对象,原对象不变。
3.NSNumbe 、NSValue 主要是为了完成  基本数据类型   ,结构体   和   对象   的互转,便于与collection配合使 (collec ion — — 集合)。
    
**************************************************
**************************************************
    NSValue 和 NSNumber
1 NSNumber   是 NSValue  的一个子类
2 NSNumber 只能包装基本数据类型。比如 int , float ,char ,等
3 NSValue 可以包装任意一个对象,包括系统自定义的数据结构,结构体等等。
    
    
    
    */
#pragma mark---------------------- 2  OC数组、字典和集合-------------------------------------------
    /*
     (一) 数组
     系统提供的数组类
数组是一个大容器,一个有序的集合,数组中可以存储不同类的对象,单必须保证存储的元素是对象
通过下标访问数据元素,下标从0开始
OC中提供了两类数组 : 一类是 NSArray (不可变数组),一类是NSMutableArray(可变数组)
可变与不可变的区别 :可变就意味着可以对原有对象进行增、删、改的操作
不可变就意味着,对象一旦被创建,内容就不可更改(元素个数和内容)
   
1 不可变数组 NSArray
 1.1不可变数组初始化创建对象   3种方法
1) 初始化方法 :initWithObjects
     NSArray *arr1 = [[ NSArray alloc]initWithObjects:@"我",@"是",@"谁", nil];
     NSLog(@"%@",arr1);
     
2 )便利构造器 :arrayWithObjects:
     NSArray *arr2 = [NSArray arrayWithObjects: @"我",@"是",@"谁",nil];
     NSLog(@"%@",arr2);
     
3) 字面量   @[   ]
     NSArray *arr3 = @[@"我",@"是",@"谁"];
     NSLog(@"%@",arr3);
//字面量方式  不需要  nil   结尾
//nil 作为数组存放元素的结束标志,多个元素通过 逗号 间隔
     
1.2不可变数组操作方法  数组都可以通过下标访问
1)求数组元素个数    . count
     NSUInteger counts = arr3.count;
     NSLog(@"%ld",counts);
     
2)  获取数组中的元素 (下标)索引 objectAtIndex
     NSString *strings1 = [arr3 objectAtIndex:2];
     NSLog(@"%@",strings1);
     
3)获取数组的第一个元素
     NSString *strings2 =[arr3 firstObject];
     NSLog(@"%@",strings2);
     
4) 获取数组的最后一个元素
     NSString*strings3 = [arr3 lastObject];
     NSLog(@"%@",strings3);
     
5 )根据元素获取对应的索引(下标),以及用来判断数组中包含某一给定的对象
     NSArray *stu1 = [NSArray arrayWithObjects:@"一",@"二",@"三",@"四",nil];
     NSUInteger index = [stu1 indexOfObject:@"四"];
     NSLog(@"%ld",index);
     
6)判断是否存在某个指定的元素
     BOOL isExist1 = [stu1 containsObject:@"一"];
     NSLog(@"%d",isExist1);
     
7) 判断两个数组是否相等(内容和长度)
     BOOL isExist2 = [stu1 containsObject:arr1];
     NSLog(@"%d",isExist2);
     
8) 将数组转化为字符串
将数组中的元素按照给定的  字符串格式  拼接成一个完整的  字符串对象
给定的字符串格式可以是任意符号,也可以是无
     NSString *string4 = [arr3 componentsJoinedByString:@"&"];
     NSLog(@"%@",string4);
     
     NSArray *arr4 = [NSArray arrayWithObjects:@"www.lanou.3g",@"五月天",nil];
     NSString *string3 = [arr4 componentsJoinedByString:@"&"];
     NSLog(@"%@",string3);
     
9)将字符串转化为数组
      按照给定的字符串进行截取,然后放入数组中
     给定的字符
     NSString *s = @"www.lanou.com";
     NSArray *arra1 = [s componentsSeparatedByString:@"."];
     NSLog(@"%@",arra1);
     
     
     
2    可变数组 NUMutableArray
2.1    3种初始化
1)初始化  initWithObjects
     NSMutableArray *mArr3 =[[NSMutableArray alloc]initWithObjects:@"1",@"2",@"3",@"4",nil];
     
2)便利器  arrayWithObjects
      NSMutableArray *mArr3 = [NSMutableArray arrayWithObjects:@"1",@"2",@"3",@"4"];
     
3)字面量
      NSMutableArray *mArr3 = [@[@"1",@"2",@"3",@"4"]mutableCopy];
     
2.2 可变数字操作方法
1)添加元素
     [mArr3 addObject:@"5"];
     NSLog(@"%@",mArr3);
     
2)  替换元素
    第一个位置是被替换的元素
    第二个位置是需要替换的内容
     [mArr3 replaceObjectAtIndex:4 withObject:@"7"];
     NSLog(@"%@",mArr3);
     
3)    交换 位置
     [mArr3 exchangeObjectAtIndex:0 withObjectAtIndex:4];
     NSLog(@"%@",mArr3);
     
4)    删除元素
(1)删除指定元素   removeObject
    若有同样的元素,相同的元素都会被删除
     
     [mArr3 removeObject:@"3"];
     NSLog(@"%@",mArr3);
     
(2) 删除全部元素
     [mArr3 removeAllObjects];
     NSLog(@"%@",mArr3);
     
(3) 删除最后一个元素  removeLastObject
(4) 删除元素根据索引   removeObjectAtindex
     
5)插入一个元素   insertObject:atlndex :
     
小结
    1 数组是用来管理一组有序元素的容器,必须保证数组中存放的都是对象,(对象的类型不受限制)而且数组中可以存放相同的元素
    容器存在的本质是为了更好的管理数据
     
     
  *********************************
   (二) 字典
字典 :  一个 无序的集合,用来存储具有一一对应关系的数据,本质上也是一个容器
字典是 字典中存储的每 个对象都是一对键值对,键值对包含两 个部分key 和 value,key 与 value的值都是对象类型。 对于每 一对key - value称为一个条 (Entry)
字典的特性 : 无序性
字典靠 key 来存取元素
     
1 不变字典
1.1 使用初始化创建对象       3种初始化
1)初始化  initWithObjects
        NSDictionary *dict1 = [[NSDictionary alloc]initWithObjectsAndKeys:@"1",@"2",@"3",@"4",@"5",@"6", nil];
     
2 )便利构造器 :arrayWithObjects
    NSDictionary *dict2 = [NSDictionary dictionaryWithObjectsAndKeys:@"1",@"2",@"3",@"4",@"5",@"6", nil];
     
3)字面量
     NSDictionary *dict3 = @{@"1":@"2",@"3":@"4",@"5":@"6"};
     NSLog(@"%@",dict3);
//  字面量中 不用 结束标志 nil  
     
1.2  字典操作方法
 1)获取字典中元素个数      @property (readonly) NSUInteger count;
     NSUInteger count = [dict3 count];
     NSLog(@"%ld",count);
     
2) 根据对应的key取对应的 value
     NSDictionary *dict4 = @{@"name":@"key",@"gender":@"key1"};
     NSString *name = [dict4 objectForKey:@"key"];
     NSLog(@"%@",name);
     
3)  取值后,并转化相应的数据类型
     char age1 = [[dict4 objectForKey:@"key"]charValue];
     NSLog(@"%d",age1);
     
4) 获取所有的key键
     NSArray *keys = [dict4 allKeys];
     NSLog(@"%@",keys);
     
 5) 获取所有的value 值
     NSArray *values = [dict4 allValues];
     NSLog(@"%@",values);
     
2    可变字典
2.1    3种初始化
     NSMutableDictionary *mDic = [[NSMutableDictionary alloc]initWithCapacity:1];
     声明可变字典的元素个数
     
1)初始化  initWithObjects
     NSMutableDictionary *dict1 = [[NSMutableDictionary alloc]initWithObjectsAndKeys:@"1",@"2",@"3",@"4",@"5",@"6", nil];
     
2 )便利构造器 :arrayWithObjects
     NSMutableDictionary *dict2 = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"1",@"2",@"3",@"4",@"5",@"6", nil];

3)字面量
     NSMUtableDictionary *dict3 = @{@"1":@"2",@"3":@"4",@"5":@"6"}.mutableCopy;
     NSLog(@"%@",dict3);

2.2 可变字典操作方法
1)   添加一个元素
     [mDic setObject:@"德玛" forKey:@"盖伦"];
     NSLog(@"%@",mDic);
工作原理 : 先查找字典中有没有对应的 key ,如果有,则修改 key 对应的 value ,如果没有,则把 key-value作为元素添加到字典中
     
2)   移除元素
     [mDic removeObjectForKey:@"盖伦"];
     NSLog(@"%@",mDic);
     
     
     
(三)   集合
特点 : 无序性 互异性
经常用重用,不区分对象
不能够存在相同的对象,集合中相同的元素操作后只剩下一个
1 不可变集合  NSSet
1.1 初始化 3种方法
1)初始化  initWithObjects
     NSSet *set0 = [[NSSet alloc]initWithObjects:@"xx",@"bb",@"cc",nil];
     
2)便利构造器 :arrayWithObjects
     NSSet *set1 = [NSSet setWithObjects:@"xx",@"bb",@"cc",nil];
     NSLog(@"%@",set1);
     
3)字面量
     NSSet *set2 = @[:@"xx",@"bb",@"cc",nil];
     
     
1.2 操作方法
1)获取集合中的任意一个元素   anyObject
     NSSet *se1  = [set1 anyObject];
     NSLog(@"%@",se1);
2)取出所有元素  allObject
3) 获取集合中元素的个数 count
4) 判断对象是否在集合中 containsObject
     
2 可变集合 NSMutableSet
2.1 初始化方法 (老三样)
1)NSMutableSet *name = [[NSMutableSet alloc]
     initWithCapacity:0];
     
2)NSMutableSet *name = [NSMutableSet
     setWithCapacity:0];
     
2.2 操作方法
1) 添加 addObject
2)删除 removeObject
     ******************************
     互异性 :集合中不能够  存在   两个相同的对象
     无序性 :对象没有先后顺序
     结合经常用来处理重用问题
     
     
     
     
     ******************************
     
数组, 字典, 集合 的区别:
相同点:都是OC中的容器类,可以存储多个元素. 但是元素必须是对象.不限制对象的类型.
不同点:
1.使用场景:
     数组:用来管理一组有序的元素的集合.
     字典:用来管理一组具有一一对应关系的数据的集合.key值在字典中是唯一的。
     集合:用来管理一组无序,并且具有互异性的元素的集合.
     可变容器类对象是不可变容器类对象的 类,在拥有 类 功能的基础上,扩充了对原有对象的增删改操作
     
 2.特点:
     数组:有序, 并且元素可以重复.
     字典:无序, key-value是字典中的一个元素.key是唯一的, 一个key只能对应一个value,但是一个value可以对应多个key.
     集合:无序, 元素具有互异性.
     
3.取值方式:
     数组:通过索引获取对应的元素.
     字典:通过key获取对应的value.
     集合:anyObject  -- 用于重用.
     
     
     
     
     
     
     
     */
#pragma mark--------------------------------类的扩展---------------------------------------------
    /*
     
能够给类添加方法的方式有下列
(1)子类化 :创建一个子类直接继承自原有类,在该类中扩充新的功能,该方式既可以扩充方法,也可以扩充实例变量 。但是,想使用扩充的功能,必须使用子类的对象,原有类的对象无扩充功能。子类继承 :必须继承父类的所有内容,然后添加自身独有的方法,可以添加实例变量,方法,不用获取原文件,  但父类无法使用新功能,所有操作只能以继承的子类来实现

(2)直接在该类中修改源代码 :这是一种最直接的添加功能的方式,但是局限于必须要拥有该类的源代码,我们才有修改的权限。该方式既可以扩充方法,也可以扩充实例变量。方便快捷,需要获取到源代码。在团队合作中,不要轻易修改源代码,需要和伙伴协商确认后,更忌讳轻易删除代码,哪怕是错误的,注释名即可。
     
     
(3)协议 :这是一种间接扩充功能的方式,协议中只有一堆方法的声明, 使用时需要类服从协议,实现协议中的方法来扩充功能, 且只能扩充方法,不能扩充实例变量。局限于必须要拥有该类的源代码。
     

(4) 类目(分类)给不能获得源代码的类添加,只能添加方法
     
(5) 延展      既能添加方法,也能添加实例变量,但是需要获取源代码。并且理论上来说,是私有的
     
(6)代理

     
1 类目 Category
1.1 Category的作用
(1) Category :也叫分类,类目。是为没有源代码的类扩充功能。
(2)扩充的功能会成为原有类的一部分,可以通过原有类或者原有类的对象直接调用,并且可继承。
(3)该方式只能扩充方法,不能扩充实例变量
     
1.2  Category的使用
使用方法 :
(1) command + n ---> objective File --->next ----> Category (文件名、文件类名、文件扩展类型)----> 填写类目名 和选择要扩充功能的类
(2)使用  类目   添加的方法首先需要在对应的类中导入    类目     的.h文件
(3)sayHi 方法是通过     类目   为 NSString类添加的一个类方法,因此该方法的调用需要NSString类名调用
(4)创建后的文件名自动 为  类名 + 类目名.h  和   类名 + 类目名.m
     
(5) .h  文件      作用:声明需要添加的方法
#import <Foundation/Foundation.h>
@interface 要扩充功能的类名    (类目名)
@end
     
(6).m  文件       作用 :实现对应的方法
#import "类目文件名.h"
@implementation  类名 (类目名)
@end
     
(7)main.m 需要导入   类目的 .h 文件
(8)要扩充功能的类中要导入  类目  的 .h文件
     
     
2 延展 Extension
2.1 Extension 的作用
(1)私有变量(方法) :类外部不能直接访问,甚至其子类也不能够直接访问
(2)延展 : 为能够获得源代码的类声明私有实例变量(方法),我们可以将.h文件中实例变量(方法)的定义过程转移到.m文件中,这个过程我们需要使用一种方法 ---延展(Exsention)
(3)延展:为能够获得源代码的类添加私有的实例变量和方法
     注 :延展操作的类必须是能够获得源代码的类(具有.m文件的类)
     
2.2 Extension的语法格式
(1)Extension 的语法格式和Category很相似,相当于把Category 的 .h 文件挪到了原始类的 .m 文件中
2.3 使用方法
(1)需要一个类 (可以获得源代码)(需要添加私有的实例变量和方法)
(2).h不变
(3).m 文件
#import “person.h”
@interface  Teacher()
     声明实例变量
     声明方法
@end
     
@implementation person
     实现方法
@end
     
(4)通过延展定义的方法属于私有方法,外界是没有访问权限的,只能在当前类的 .m 文件中访问
(5) 如何调用   写共有方法
.h 文件      声明
     
.m 文件   
@implementation person
-(void)publicName : (类型 )参数
{
     [self 所添加的方法名:参数];
}
     
//示例代码
-(void)public:(NSMutableArray *)array
{
        [self removeArray:array]
     
}
@end
     

     
     
对比  Category 作用 :   为没有源代码的类添加方法                    格式    : 定义一对 .h 和.m
          Extension  作用 :管理类私有方法                                        格式    : 把代码写到原始类的 .m 中
     
延展 ,声明的可见度都是私有的,只能访问本类
            既可以添加方法,也可以添加实例变量
            需要能够获得到源代码的情况下
     
3 delegate 设计模式
3.1
(1)delegate 设计模式的使用我们首先需要明白三个要素-委托方,代理方,协议
委托方:委托别人去执行某些操作的人(对象)
协议:(protocol)委托方需要代理方执行的操作
代理方:被委托去执行某些操作的人(对象)
(2)协议是一套标准(一堆方法的声明),只有 .h 文件。协议的定义以@protocol开始,以@end结束。
     协议写在 .h 文件中
(3)协议中的方法默认 是必须实现的,既@required。关键字@optional修饰的方法是可选的,可实现也可不实现
   
3.2 实现方法
(1)建立委托方(一对.m和.h)和代理方(一对.m和.h);
(2)在委托方的  .h 文件中,  声明一个协议
#import <Foundation/Foundation.h>
     
//     声明协议
@protocal  协议名 <NSObject>
     
//     默认是必须实现 的 @required
声明一系列方法(清单)
//     可选 @optional
     
@end
     
@interface 类名(A类):NSObject
//     任意一个遵守了这个协议的对象,都可以成为当前的一个代理
@property(strong,nonatomic) id<协议名>delegate      修饰用assign
     
@end
     
(3)签订协议(在代理人的 .h 文件中引入协议所在的类)(在代理人的 .m 文件中实现协议中的方法)
在 代理人的 .h 的文件中
#import <Foundation/Foundation.h>
#import "类名.h(A类)" ;//引入委托方的类(A类)既协议所在的类
     
@interface 类名(B类):NSObject<协议名>
@end
     
在代理人的 .m  的文件中
#import "类名.h(B类)"
@implementation 类名(B类)
     
实现协议中的方法
     
@end
     

     
  总结:
1)委托人(A类)声明协议
2)某人(B类)遵守对应的协议,并且实现了协议里面的方法,那么B就是A的代理
3)委托人(A类)让代理去执行协议里面的方法(这些方法可能会有参数和返回值)
     
     
     */
#pragma mark----------------------------------NSDate--------------------------------------------
    /*

     
//     1 获取系统当前时间
//     获取的始终是0时区的时间  [NSDate date] 直接获取
    NSDate *nowDate = [NSDate date];
    NSLog(@"current time:%@",nowDate);
    
//    2    NSLocale   获取当前时区
    NSString *theCurrentTimeZone = [nowDate descriptionWithLocale:[NSLocale currentLocale]];
    NSLog(@"The current time zone = %@",theCurrentTimeZone);

//     3   获取东八区的时间(其他时区的时间)   dateWithTimeIntervalSinceNow
//    传入的参数 :时区*每小时多少分钟*每分钟多少秒
    NSDate *eightAreaDate = [NSDate dateWithTimeIntervalSinceNow:8*60*60];
    NSLog(@"eightAreaDate =  %@",eightAreaDate);
    
//     4    获取明天的当前时间
    NSDate *tomorrowDate = [NSDate dateWithTimeIntervalSinceNow:(8+24)*60*60];
    NSLog(@"tomorrowDate = %@",tomorrowDate);

//    5  NStimeInterval  时间间隔,是一个以秒为单位的浮点类型数据
    NSTimeInterval timeInterval = [nowDate timeIntervalSince1970];
    NSLog(@"timeLnterval = %f",timeInterval);
    
    NSTimeInterval timeIntervalNow = [nowDate timeIntervalSinceNow];
    NSLog(@"timeIntervalNow = %f",timeIntervalNow);
    
    NSDate *date1 = [NSDate dateWithTimeIntervalSinceNow:timeInterval];
    NSLog(@"date = %@",date1);
    
    NSTimeInterval betweenTime = [tomorrowDate timeIntervalSinceDate:nowDate];
    NSLog(@"betweentime = %f",betweenTime);



//    当前时间
    NSDate *nowDate1 = [NSDate date];
    NSLog(@"nowDate = %@",nowDate1);

//    6  固定时间       dateWithTimeIntervalSinceNow
    NSDate *oneDate = [NSDate dateWithTimeIntervalSinceNow:60*60];
    NSLog(@"oneDate = %@",oneDate);
    

//    7 NSDateFormatter   指定日期格式
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init ];
//    分配内存   存放格式
    
    //7.1  设置日期格式  setdateFormatter
    [dateFormatter setDateFormat:@"GGGGyyyy年MM月dd日 HH时mm分ss秒 aaa QQQQ EEE"];
//    定义格式
    
    NSString *formatterDate = [dateFormatter stringFromDate:nowDate];
    NSLog(@"%@",formatterDate);
    
    //      设置日期类型
    [dateFormatter setDateStyle:NSDateFormatterMediumStyle];
    
    //7.2  将日期转换为字符串
    NSString *stringDate = [dateFormatter stringFromDate:nowDate];
    NSLog(@"stringDate = %@",stringDate);

    //7.3  字符串转换日期
    NSDateFormatter *formatterDateNow = [[NSDateFormatter alloc] init];
    [formatterDateNow setDateFormat:@"yyyy年MM月dd日HH时mm分ss秒"];
    NSString *string = @"2016年6月6日14时45分23秒";
    
    NSDate *dateFromString = [formatterDateNow dateFromString:string];
    NSLog(@"dateFromstring = %@",dateFromString);

    
    



   


//    日期格式与字符串转换
    
     
     
//     NSDate的适用 : NSTimer 定时器类经常会使用到
    
     
     
         */
#pragma mark------------------------OC遍历和排序--------------------------------------------------
    /*
1 遍历   
集合(Collection):OC中提供的容器类,数组,字典,集合
遍历 :对集合中元素依次取出的过程叫做遍历
三种方式 : for循环遍历      NSEnumerator 遍历     for....in 遍历
     
1)遍历数组
    NSArray *array = @[@"number1",@"number2",@"number3",@"number4",@"number5"];
    for (NSUInteger i = 0; i < array.count; i++) {
        NSString *value = [array objectAtIndex:i];
        NSLog(@"%@",value);
    }
***********
对象数组和C语言中一样可以使用下标访问,可也以通过数组操作方法
     
2)遍历字典

    NSDictionary *dictionary  = @{@"key1":@"value1",@"key2":@"value2",@"key3":@"value3",@"key4":@"value4"};
    
    NSArray *allKeys = [dictionary allKeys];
    
    for (NSUInteger i = 0; i < allKeys.count; i++) {
        NSString *key  = [allKeys objectAtIndex:i];
        
        NSString *value = [dictionary objectForKey:key];
        
        NSLog(@"%@",value);

    }
原理:先获取字典中所有的key,存储到数组中,遍历数组依次取出key,然后根据key从字典张取出对应的value
    

     
3)  遍历集合
   
    NSSet *set = [NSSet setWithObjects:@"number1",@"number2",@"number3",@"number4", nil];
    
    NSArray *allObjects = [set allObjects];
    
    for (NSUInteger i = 0; i < allObjects.count; i++) {
        NSString *value = [allObjects objectAtIndex:i];
        
        NSLog(@"%@",value);

    }
原理 :用集合的allObjects 属性先渠道集合的所有元素存储到数组中,再通过for循环的循环变量用作下标来渠道每个元素
     
2  使用for循环 排序数组---OC
     
    NSMutableArray *array = [@[@"2",@"a",@"我",@"20",@"无敌"]mutableCopy];
    
    for (int i = 0; i < array.count - 1; i++) {
        for (int j = 0; j < (array.count - 1 - i); j++) {
            if ([array[j] compare:array[j+1]]) {
                [array exchangeObjectAtIndex:j withObjectAtIndex:(j+1)];
            }
        }
    }
    NSLog(@"%@",array);

     
3 枚举器  NSEnumerator
枚举器,遍历集合中的元素。
依附于集合类(NSArray ,NSSet ,NSDictionary),没有用来创建实例的接口。
NSEnumerator的nextObjec 方法可以遍历每个集合元素,结束返回nil,通过与while结合使用可遍历集合中所有元素。
对可变集合进行枚举操作时,不能通过添加或删除对象    这类方式来改变集合容器的元素个数
     
注 : 枚举器的nextObject方法只能取出一个对象,所以需要和while循环结合
     
3.1 枚举器遍历数组
     
     NSArray *array = @[@"1北京",@"2上海",@"3广州",@"4深圳",@"5蓝鸥"];
//枚举器正序遍历
     NSEnumerator *rator = [array objectEnumerator];
     
     id value = 0;
     while (value = [rator nextObject])
     {
        NSLog(@"%@",value);
     }
     
//    枚举器倒序遍历
    NSArray *array = @[@"1北京",@"2上海",@"3广州",@"4深圳",@"5蓝鸥"];
    NSEnumerator *rator = [array objectEnumerator];
    
    id value = 0;
    while (value = [rator nextObject]) {
        NSLog(@"%@",value);

    }
    
3.2 枚举器遍历字典 value值
    NSDictionary *dict = @{@"a":@"b",@"c":@"d",@"x":@"y"};
    NSEnumerator *rator = [dict objectEnumerator];
    
    id value = 0;
    while (value = [rator nextObject]) {
        NSLog(@"%@",value);

    }
//     不嫩出现相同的value值
//     由于字典中存储的元素是无序的,因此美誉反向枚举的概念
    
3.3 枚举器遍历集合
    NSSet *set = [NSSet setWithObjects:@"number1",@"number2",@"number3",@"number4", nil];
    NSEnumerator *rator = [set objectEnumerator];
    
    id value = 0;
    while (value = [rator nextObject]) {
        NSLog(@"%@",value );

    }
//     由于集合中存储的元素是无序的,因此美誉反向枚举的概念
 
     
4 for in    的使用
*************快速枚举,是在NSEnumerator的基础上封装的更加方便的快速的遍历集合元素的方式
*********对可变集合进行枚举操作时,不能通过添加或删除对象    这类方式来改变集合容器的元素个数
     
4.1 格式:
     for (集合中对象的类型 *元素名 in 被遍历的集合)
     {
        语句;
     }
4.2 遍历数组
    NSArray *array = @[@"1北京",@"2上海",@"3广州",@"4深圳",@"5蓝鸥"];
    for (NSString *string in array) {
        NSLog(@"%@",string);

    }
4.3 遍历字典
     NSDictionary *dict = @{@"a":@"b",@"c":@"d",@"x":@"y"};
    for (NSString *string in dict) {
        NSLog(@"%@",string);

    }
//    字典单独使用可以相同 的value 值
//     在 for in 里面。若字典有相同 的value 值,只会打印一个

4.4  遍历集合
    NSSet *set = [NSSet setWithObjects:@"number1",@"number2",@"number3",@"number4",@"number5", nil];
    for (NSString *string in set) {
        NSLog(@"%@",string);

    }
    
5 数组排序
5.1compare排序    sortUsingSelector
 1)系统方法compare
     
不可变数组排序     sortedArrayUsingSelector 是有返回值的,返回值既是排序后的数组
    NSArray *array = @[@"1北京",@"2上海",@"3广州",@"4深圳",@"5蓝鸥"];
    [array sortedArrayUsingSelector:@selector(compare:)];
    NSLog(@"%@",array);
     
可变数组排序     sortUsingSelector      无返回值,改变调用这个方法的数组本身
    NSMutableArray *array = @[@"1北京",@"2上海",@"3广州",@"4深圳",@"5蓝鸥"].mutableCopy;
    [array sortedArrayUsingSelector:@selector(compare:)];
    NSLog(@"%@",array);
     
2)//自定义方法  compare
     
     
//     不可变素组 (compare 排序)
    
    Person *p1 = [Person personWithName:@"a" Sex:@"m" Age:23];
    Person *p2 = [Person personWithName:@"b" Sex:@"f" Age:5];
    Person *p3 = [Person personWithName:@"c" Sex:@"m" Age:25];
    Person *p4 = [Person personWithName:@"d" Sex:@"f" Age:20];
    
//自定义方法  compare
    NSArray *personArray = [NSArray arrayWithObjects:p1,p2,p3,p4, nil];
    NSArray *arr = [personArray sortedArrayUsingSelector:@selector(comparaByAge:)];
    NSLog(@"%@",arr);

//5.2  生成排序描叙符         sortUsingNSSortDescriptor
//1)不可变数组
    NSSortDescriptor *sortWithName = [[NSSortDescriptor alloc]initWithKey:@"name" ascending:NO];
//    生成排序描述符
    
    NSArray*array = [personArray sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortWithName]];
// sortWithName 中有key  ascending 等3个参数   key()
//NSArray  array = [NSArray arrayWithObjects:sortWithName,sortWithSex,sortWithAge]
    
    NSLog(@"%@",array);

    NSSortDescriptor *sortWithAge = [[NSSortDescriptor alloc]initWithKey:@"age" ascending:NO];
    NSArray *array1 = [personArray sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortWithAge]];
    NSLog(@"%@",array1);
    
    NSSortDescriptor *sortWithsex = [[NSSortDescriptor alloc]initWithKey:@"sex" ascending:NO];
    NSArray *array2 = [personArray sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortWithsex]];
    NSLog(@"%@",array2);
    
//2) 可变数组
    
//自定义方法  compare
    NSMutableArray *personMuArray =[NSMutableArray arrayWithObjects:p1,p2,p3,p4, nil].mutableCopy;
    [personMuArray sortUsingSelector:@selector(comparaByAge:)];
    NSLog(@"%@",personMuArray);
    
//    生成排序描叙符  NSSortDescription
    [personMuArray sortUsingDescriptors:[NSMutableArray arrayWithObject:sortWithName]];
    NSLog(@"%@",personMuArray);
    
    [personMuArray sortUsingDescriptors:[NSMutableArray arrayWithObject:sortWithAge]];
    NSLog(@"%@",personMuArray);

    [personMuArray sortUsingDescriptors:[NSMutableArray arrayWithObject:sortWithsex]];
    NSLog(@"%@",personMuArray);
    
     
//注 :SEL 类型的参数是 comparator :需要传入一个返回结果是NSComparisonResult
    
          */
#pragma mark--------------------------内存管理0--------------------------------------------------
    /*
 1  **********************************内存溢出和内存泄露*****************************************
     内存溢出 out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出。
     
     内存泄露 memory leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。
     
     memory leak会最终会导致out of memory!
     
     内存溢出就是你要求分配的内存超出了系统能给你的,系统不能满足需求,于是产生溢出。
     
     内存泄漏是指你向系统申请分配内存进行使用(new),可是使用完了以后却不归还(delete),结果你申请到的那块内存你自己也不能再访问(也许你把它的地址给弄丢了),而系统也不能再次将它分配给需要的程序。一个盘子用尽各种方法只能装4个果子,你装了5个,结果掉倒地上不能吃了。这就是溢出!比方说栈,栈满时再做进栈必定产生空间溢出,叫上溢,栈空时再做退栈也产生空间溢出,称为下溢。就是分配的内存不足以放下数据项序列,称为内存溢出.
     
     以发生的方式来分类,内存泄漏可以分为4类:
     
     1. 常发性内存泄漏。发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏。
     2. 偶发性内存泄漏。发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。
     3. 一次性内存泄漏。发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块仅且一块内存发生泄漏。比如,在类的构造函数中分配内存,在析构函数中却没有释放该内存,所以内存泄漏只会发生一次。
     4. 隐式内存泄漏。程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。
     
     从用户使用程序的角度来看,内存泄漏本身不会产生什么危害,作为一般的用户,根本感觉不到内存泄漏的存在。真正有危害的是内存泄漏的堆积,这会最终消耗尽系统所有的内存。从这个角度来说,一次性内存泄漏并没有什么危害,因为它不会堆积,而隐式内存泄漏危害性则非常大,因为较之于常发性和偶发性内存泄漏它更难被检测到
    
2 有一个对象的所有权叫做 own     对象的拥有者个数至少为1    对象才得以存在    否则应立即被销毁
cocoa 设立判断所有权的标志
****只有当你对一个对象做了 alloc ,copy ,或 retain 等操作以后,你才拥有它的所有权
****当你不再需要这个对象时,你应当释放你的所有权
****你不可以对你没有所有权的对象执行释放操作
     
     
3  内存管理对象
     值类型: 比如 int float struct 等基本数据类型 苹果内部自己管理。原因是内存都放在栈上面,是一块连续的存储地。遵循先进后出的原则。
     
     引用类型: 是继承NSObject类的所有OC对象。内存需要自己管理。(事故重发地),原因是内存放在堆上面,彼此之间有内存空隙,不是连续的。如果不管理收回,容易引起内存泄漏或者野指针的问题。
     
     堆内存和栈内存之间的特点
     堆内存 空间大,不连续
     栈内存 空间小,连续,数量过大影响性能
     
     */
#pragma mark--------------------------内存管理1--------------------------------------------------
    /*
     (一)内存管理方式
     1 Crash(闪退)   90%的原因是因为内存问题
     2 内存问题体现两个方面 : 内存溢出      野指针异常
     2.1 iOS给每个应用程序分配了一定的内存,用于程序的运行,一旦超出内存上限,程序就会Crash
     
     ****** iPhone3GS内存30M左右,iPhone5s内存80M左右,iPhone6之后是100M左右
     
     *******3.5寸非Retina屏幕(320*480),
     一张全屏图,占用字节数 329*480*4
     一个像素占4个字节,存放RGBA,既 600 Bytes
     iPhone 3GS同时读取60张图片就会Crash
     
     *********4寸屏幕(320*568)实际像素 640 * 11136
     一张全屏图,占用字节数 640 * 1136 *4既2.77 Mbytes
     iPhone 5s 同时读取40张图片就会Crash
     
     ***********    4.7寸屏幕(375*667)实际像素750*1334
     一张全屏图片,占用字节数750*1334*4 既3.82M Bytes
     iPhone 6 同时读取27张图片就会Crash
     
     *********    5.5屏幕(414*736),实际像素1080*1920
     程序存放全屏图,占用字节数1080*1920*4,既7.91M bytes
     iphone 6 同时读取131张图片就会Crash
     
     ********* iOS6之后,系统分给每一个APP的大小是100M左右,运行期间使用内存超过这个上限,立即Crash
     
     2.2 野指针:对象的内存已经被系统回收,但是仍然使用指针操作这块内存。
     代码量越大,程序越容易出现野指针问题
     *****访问没有所有权的内存,如果想要安全的访问,必须确保空间还在
     
     2.3 过度释放 :在同一块引用计数为1的内存释放多次。立即Crash
     
     2.4 内存泄露 :空间使用完之后没有及时的返回系统
     
     6 垃圾回收机制(Garbage - Collection)
     MRC(Manual Reference Counting)
     ARC(Auto Reference Counting)
     
     垃圾回收机制:程序员只需要开辟内存空间,不需要 代码的 形式释放,系统来判断哪些空间不再被使 ,并回收这些内存 空间,以便再次分配。整个回收的过程不需要写任何代码,由 系统 动完成垃圾回收。Java开发中一直使用的就是垃圾回收 技术。
     
     MRC(Manual Reference Counting)
     人工引用计数:内存的开辟和释放 都由程序代码进 控制。相对垃圾回收来说,对内存的控制更 加灵活,可以在需要释放的时候及时释放,对程序员的要求较 高,程序员要熟悉内存管理的机制
     
     ARC(Auto Reference Counting)
     自动引用计数:iOS 5.0的编译器特性,它允许用户只开辟空间,不用去释放空间。它不是垃圾回收!它的本质还是MRC,只是编译器帮程序员默认加le释放的代码。
     
     iOS 支持两种内存管理方式:ARC和MRC
     MRC的内存管理机制是:引用计数
     ARC是基于MRC的
     ******************************************
     内存管理黄金法则:
     如果你对一个对象做了 alloc,copy,retain操作之后,你就有了对象的所有权,你就有责任对它进行release或者autorelease
     简单来说: 只要自己使用了增加引用计数的方法,那就必须使用数量对等的减少方法,如果没有使用,和自己无关,不用处理
     
     
     (二)引用计数机制
     **** C语言中,使用malloc 和 free ,进行堆内存的创建和释放
     ****堆内存只有正在使用和销毁两种状态
     ****实际开发中,可能遇到连个以上的指针使用同一块内存
     ****C语言无法记录内存使用者的个数
     
     1 OC对象的操作       生成对象   持有对象           释放对象                                                销毁对象
     OC中对应的方法        +alloc      -retain            -release/-autorrealease                      -dealloc
     
     *********************************************
     让引用计数发生改变的方法:
     1)   +alloc :在堆区开辟内存空间,让被开辟的内存的空间的引用计数从0 变为1
     2)  -retain :将原有对象的引用计数加1
     3)   -copy  : 把某一对象的内容拷贝一份,拷贝出新的对象,会在堆区开辟新的空间,原有对象的引用计数不变,新的对象的引用计数变1
     4)   -release :将原有对象的引用计数立即减1
     5)   -autorelease 未来的某一时刻引用计数减1
     如果对象之前引用计数为4,autorrelease之后任然为4,未来某个时刻会变为3
     *****************************************************
     2  通过autoreleasepool自动释放池,控制autorelease对象的释放
     向一个对象发送autorelease消息,该对象就会被添加到离 autorelease 最近的自动释放池中,当自动释放池销毁时,为池中的每个对象发送 release 消息
     
     ****iOS5 之前,使用NSAutoreleasePool 自动释放池类创建对象
     NSAutoreleasePool  *pool = [[NSAutoreleasePool alloc]init];    //自动释放池创建
     [pool release]; //自动释放池销毁
     
     ***********在iOS5之后,不再推荐使用NSAutreleasePool 类,使用 @autoreleasepool{ }替代
     出了大括号,自动释放池才向各个对象发送release消息
     
     @autoreleasepool{
     自动释放池创建
     }自动释放池销毁
     
     3   dealloc
     -dealloc 是继承自父类的方法,当对象引用计数为0的时候,由对象自动调用,销毁该对象的空间
     重写dealloc方法,验证对象的空间是否被回收
     -(void)dealloc{
     NSLog(@“%@对象被销毁”,self);
     [super dealloc];//父类对该方法的实现才是真正的回收空间
    //这个方法必须写在dealloc 中最靠下的位置,因为它下面的代码不再执行
     }
     
     
     (三)内存管理原则
     1 凡是使用了alloc、retain或者copy让内存的引用计数增加了,就需要使用release或者autorelease让内存的引用计数减少。在一段代码内,增加和减少的次数要相等
     2  如果增加的次数大于减少的次数,会造成内存泄露
     3  如果增加次数小于减少的次数,会造成过度释放
     4 如果增肌的次数等于减少的次数,还继续访问,造成野指针问题
对应关系 : alloc 和autorelease  对应
                     retain 和release        对应
  Person *person = [[[Person alloc]init]autorelease];

     
**************************************************************************
     //        第一种
     //        Person *p1 = [Person new];
     //        Person *p2 = p1;
     //        Person *p3 = p2;
     //        [p1 release];// 1-0  空间回收
     //        [p2 release]; //过度释放
     
     //        第二种
     //        Person *p1 = [Person new];
     //        Person *p2 = [p1 retain];
     //        Person *p3 = [p2 retain];
     //
     //        NSLog(@"%lu",p2.retainCount);
     //        [p2 release];
     //        [p2 release];
     //        [p2 release];
     //
     //        p1 = nil;
     //        p2 = nil;
     //        p3 = nil;
     //      最终目的:是想回收堆区的内存空间,所以需要通过指针变量访问到堆区的内存,并且修改引用计数。最后记得将指针置空
     
     //        第三种情况
     //        Person *p1 = [Person new];
     //        Person *p2 = [Person new];
     ////        直接或间接出现以下情况,内存空间相同
     //        p1 = p2;//指向了同一块内存,特征同情况一
     
     //        第四种情况:
     //        NSString *string = [[NSString alloc]initWithFormat:@"lanou"];
     //        [string retain];
     //        [string retain];
     //
     //        string = @"lanxiang";//指向常量区
     //        [string release];
     //        [string release];
     //        [string release];
     //        %lu 打印常量区内存时。输出结果是第一个无穷大的数
     //        %ld 打印常量  区内存时。输出结果是 -1
     //        常量区内存不能release
     //        NSLog(@"%lu",string.retainCount);
 ****************************************************************************************
 
     ************************************************************
    增加和减少的方法  成对书写,然后再去写功能代码
     
        问? 1 为什么本该引用计数为0的,却最终为1?
        引用计数只是告诉系统是否需要回收空间,当最后一次release时,发现引用计数已经为1,说明只有自己在使用,所以直接回收空间即可,不会再将引用计数置为0;
     
     
        问?2 空间回收了吗
        重写该类的 dealloc 方法,看是否调用,只要调用了,就被回收了
     
        Person *per = [[[Person alloc]init]autorelease];
        [per retain];
        代码段
        [per release];
     **************************************************************
     (四)协议
     
     Protocol(协议),是 iOS开发中常用的技术
     ****协议是一套标准(一堆方法的声明),只有 .h文件 。
     *****接受协议的类   实现协议中定义的方法
     ****协议中的方法默认是必须实现的   既@required   关键字@optional 修饰的方法是可选的,可实现也可不实现
     1)第一种
     1 协议的定义 :
     Command + n ———>选择OS X下的 source ————>objective - C  File --->Next --->弹出选项
     2 协议的方法
     协议的方法有两种,一种必须实现的@required,另一种可选择实现的@optional
     默认方法就是必须实现的
     #import <Foundation/Foundation.h>
     @protocol SayHello <NSObject>
        
     @required
     -(void)sayHello;
     
     @optional
     -(void)sayByeBye;
     
     @end

在 .h文件中
     #import <Foundation/Foundation.h>
     #import “SayHello.h”
     @interface Person  : NSObjext<SayHello>
    方法声明
     @end
     
     2)第二种
     #import <Foundation/Foundation.h>
     
     @protocol Sayhello <NSObject>
     
     方法声明
     
     @end
     
     @interface Person  : NSObjext<SayHello>
     
     @end

     写在@interface 文件外面
     
     
     (五)拷贝:
》》对一个对象发送 copy消息,对象就会去找 copywithzone 方法并且执行
》》copy 的原理 : 生成一个新的对象,并且使新对象的引用计数为1,他不改变原始对象的引用计数

》》跟retain 不同, 一个对象想要copy, 生成自己的副本, 需要服从NSCopying 协议,定义copy的细节(如何copy)。如果类没有接受NSCopying协议而给对象发送 copy 消息,会引起crash
     
1格式书写
     *********************************
     //     Person.h 文件    服从NSCopying  协议
     @interface Person :NSObject<NSCopying>
     在类的 .h 文件中,在当前类父类的后面使用一对尖括号,遵循协议,一个类可以遵循多个协议,每个协议用逗号隔开
     //     方法
     @protocol NSCopying
     -(id)copyWithZone :(NSZone *)zone;
     @end
     ********************************
     根据copyWithZone :方法的实现不同,拷贝分为三种类型:
     伪拷贝   浅拷贝   深拷贝
     
     1 伪拷贝
          拷贝地址,相当于 retain 操作 ,引用计数加 1
     -(id)copyWithZone :(NSZone *)zone
     {
     return [self  retain];
     }
     
     Person *p1 = [[Person alloc]init];
     p1.name = @"liuhui";
     p1.gender = @"男";
     
     Person *p2 = [p1 copy];


     2 浅拷贝
     对象开辟新的空间,但是两个对象的实例变量指向同一块空间
     -(id)copyWithZone :(NSZone *)zone
     {
     Person *copyPer = [[Person allocWithZone: zone]init];
     copyPer.name = self.name;
     copy.gender = self.gender;
     return copyPer;
     }
     
     3 深拷贝
     对象开辟新的空间,两个对象的实例变量也指向不同的空间
     -(id)copyWithZone:(NSZone *)zone
     {
     Person *copyPer = [[Person allocWithZone: zone]init];
     copyPer.name = [self.name mutableCopy];
     copyPer.gender = [[self.gender mutableCopy]];
     return copyPer;
     
     }
     
     ********************************************************************************
     copy:对于可变对象为深复制,引用计数不改变;
                   对于不可变对象是浅复制,引用计数每次加一。始终返回一个不可变对象。
     ********************************************************************************
     mutableCopy:始终是深复制,引用计数不改变。始终返回一个可变对象。
     
     不可变对象:值发生改变,其内存首地址随之改变。
     可变对象:无论值是否改变,其内存首地址都不随之改变。
     引用计数:为了让使用者清楚的知道,该对象有多少个拥有者(即有多少个指针指向同一内存地址)。
     ************************************************************************************
     
     Copy什么时候使用?
     
     1、不可变对象→可变对象的转换:
     
     NSArray *array1= [NSArray arrayWithObjects:@"a",@"b",@"c",@"d",nil];
     
     NSMutableArray  *str2=[array1 mutableCopy];
     
     2、可变对象→不可变对象的转换:
     
     NSMutableArray *array2   = [NSMutableArray arrayWithObjects:@"aa",@"bb",@"cc",@"dd",nil];
     
     NSArray *array1=[array2  copy];
     
     3、可变对象→可变对象的转换(不同指针变量指向不同的内存地址):
     
     NSMutableArray *array3 = [NSMutableArray arrayWithObjects:@"a",@"b",@"c",@"d",nil];
     
     NSMutableArray  *str2 = [array3 mutableCopy];
     深拷贝是在要将一个从可变(不可变)转化为不可变(可变),或者将一个对象复制一份时候用
     浅拷贝:是在赋值一个对象的指针时用到
  **************************************************************************
     总结 :
     
     OC借助引用计数机制去管理内存,凡是使 了alloc、copy、retain 等方法,增加了引用计数,就要使用release和autorelease 减少引用计数,引用计数为0的时候,对象所占的内存,被系统回收。
     autorelease是未来某个时间(autoreleasepool销毁)引用减一 ,不是即时的。
     不是任何对象都可以接收copy消息,只有接受了NSCopy协议的对象才能接收copy消息。
     
     
     
     (六)
6.1  @class
1 引入一个类的两种方法
     @class:如果你只是定义成员变量、属性
     #impor :如果是继承某个类
     
2 区别
     @class :只是类的声明,告诉编译器在A.h文件中,具体这个类有什么,不需要知道
     #import : 会包含被引用类的所欲信息,包括被引用类的变量和方法
3 import<Foundation/Foundation.h> 是为了知道框架里有什么成员和方法,避免重复定义
     
4  使用@class方式由于只需要知道被引用类(B类)的名称就可以了,而在实现类由于要用到被引用类中的实体变量和方法,所以在.m文件中需要使用#import来包含引用类的头文件。
     
如果又上百个头文件都#import同一个文件,或者这些文件依次被#import,那么一旦最开始得头文件改动,后面引用到这个文件的所有类都需要重新编译一遍,这样的效率也可想而知的,而相对来讲,使用@class方式就不会出现这种问题。
当出现循环依赖干系的时候,#import会报错。
     

     注 : class 后面只是一个字符串作用 :告诉编译器这个字符串先当做类区使用,该类中的具体信息无法获取
     如果要调用方法等,就需要导入头文件
     
@class Man; //@class只是告诉编译器,后面的字符串代表的是一个类,但是里面有什么数据不知道,将它(字符串)去当一个完整的类使用
     //一般在.h中是使用@class对类进行声明,然后如果你想使用这个实例变量或者它本身具有的方法时,必须要在其.m文件中,使用 #import 引入该类
     //正常情况下:  @class(.h文件声明) 和 #import(.m文件引入) 配套使用
     
     
     
     
     
    */
#pragma mark--------------------------内存管理2--------------------------------------------------
    /*
1 属性的内存管理
     语义特性 : assign     retain      copy
assign  使用范围:基本数据类型(char,short,int,float,double)
retain   使用范围:对象类型
copy    使用范围 : 对象类型,且遵守了<NSCopying>协议
     
1.1 属性的内部实现
(1) assign 下的属性内部实现
@property (assign,nonatomic)NSString *name;
*******     setter
-(void)setName :(NSString *)name
{
        _name = name;
     }
     
********     getter
-(NSString *)name
     {
        return _name;
}

(2)retain 下的属性内部实现
@property (assign,nonatomic)NSString *name;
 *******    setter
-(void)setName :(NSString *)name
{
        if(_name != name){
     
            [_name release];
     
            _name = [name retain];
        }
     }
     
*******     getter
-(NSString *)name
     {
     return [[_name retain]autorelease];
}

(3)copy 下的属性内部实现
@property (assign,nonatomic)NSString *name;
*******    setter
-(void)setName :(NSString *)name
{
     if(_name != name){//判断地址是否相同
     
     [_name release];//如果不相同,将旧地址释放
     
     _name = [name copy];//将新的对象赋值,引用计数加1,原有对象不变
        }
}
     
*******     getter
-(NSString *)name
{
     return [[_name retain]autorelease];//防止内存泄露
}
     
//     注 :如果要对一个对象进行copy操作,那该对象所属的类必须遵守<NSCopying>
     
     
2 dealloc 释放实例变量
dealloc 是 NSObject 的一个实例方法,用于回收 alloc开辟的内存空间
这个方法在对象引用计数为0时,由系统自动调用
通常我们在 dealloc 中释放类的是实例变量
     实现格式
-(void)dealloc
{
     [super dealloc];
}
******永远不要手动调用 dealloc
******在dealloc方法的最后一行,必须要写 [super dealloc] ,让系统正真的去销毁对象
     
3 便利构造器的内存管理
+(id)personWithName:[NSString *]name
{
        person *p = [[Person alloc]initWIthName : name];
        return [p autorelease];
}
     
4 集合的内存管理 NSArray NSDictionary NSSet
集合会自主管理集合内部元素
集合内存管理的方式:
加入集合的元素会被 retain ; 移除集合的元素会被 release ;集合被释放后,会对集合中所有元素 release
     
5 KVC
Key   Value Coding 键值编码 ,是一种间接访问实例变量的方法
KVC 提供了一种使用字符串(key)而不是访问器方法,去访问一个对象实例变量的机制
5.1 方法
(1)-(id)valueForKey :(NSString *)key;*******************************取值
(2)-(void)setValue :(id)value   forkey:(NSString *)key;     *******赋值
//kvc 通过setValue : forKey进行赋值的时候,优先去类中查找 “ _key ”对应的实例变量,如果有,直接赋值,如果没有,再找为“key”的对象,进行赋值
     
//     代码示例
     Person *p = [Person new];
     [p setValue:@"xiaoming" forKey:@"name"];
     NSLog(@"%@",[p valueForKey:@"name"]);
     
(3)-(id)valueForKeyPath :(NSString *)keyPath;*********************************取值
(4)-(void)setValue : (id)value      forKeyPath:(NSString *)keyPath;********赋值    Path 地址
//根据路径给实例变量/属性赋值。不同路劲之间用 “ . ”间隔开
     
//     代码示例
     Man *man = [Man new];
///给类中的属性(对象)开辟空间
     man.woman = [Woman new];
     [man setValue:@"fangfang" forKeyPath:@"woman.name"];
     NSLog(@"%@",[man valueForKeyPath:@"woman.name"]);
     
     
//当使用 KVC 时 , 如果 key 值和属性名不一样时 ,就会崩溃。
//// 如果没有找到对应的值,系统会默认调用 valueForUnderFinedKey,抛出异常(崩溃),所以需要我们重写一下,让它返回空,不要崩溃(重写以下两个方法)

-(void)setValue :(id)value   forUndefinedKey:(NSString *)key
    {
        NSL(@“没有找到”);
     }
     
************************
-(id)valueForUndefinedKey:(NSString *)key
    {
        NSL(@“没有找到”);
        return nil;
     }
     
(5)-(void)setValuesForKeysWithDictionary:(NSDictionary *)keyedValues
     
     示例代码
    Person *p = [Person new];
     NSDictionary *dict = @{@"name":@"chenbo",@"gender":@"nan"};
     p.name = [dict objectForKey:@"name"];
     NSLog(@"%p",p.name);
     p.gender = [dict objectForKey:@"gender"];
     NSLog(@"%p",p.gender);
     
     [p setValuesForKeysWithDictionary:dict];
     NSLog(@"%@ %@",p.name,p.address);
     
     
KVC 总结:
赋值原理 : 给定一个 Key,比如说 name
(1) 先查找对象中有没有对应的 setName : 方法,如果有,直接调用该方法,如果没有,转步骤(2);
(2)查找对象中有没有定义实例变量 _name ,如果有,直接赋值。否则转步骤三
(3)自动调用对🐘中的方法 :setValue :forUndefinedKey ;
注 : setValue :forUndefinedKey ;是默认实现的方法,被调出时抛出异常(崩溃),如果不想崩溃的话,需要手动重写该方法,让它返回空
     
取值原理 :步骤同上赋值
     
注 : -(void)setValue :(id)value   forUndefinedKey:(NSString *)key
        -(id)valueForUndefinedKey:(NSString *)key
        只要写后面一个即可
     
     
6 ARC
ARC:Automatic Reference Counting,自动引用计数,由开发人员开辟 内存空间,但是不需要释放该内存空间,由系统自动释放该空间。 ARC本质上还是基于MRC的,只不过是系统自动添加了释放内存的方法。 ARC是编译器特性, 而不是运行时特性,更不是垃圾回收器(GC)。 从Xcode5.0后,创建的工程默认是开启ARC的
     
当工程开启ARC后,由于编译器会自动帮你释放内存,所有和内存相关操作retain、release、autorelease,都不能写
当重写dealloc方法时,也不能写[super dealloc],否则会报错
     
6.1语义特性
     assign    :基本数据类(char,short,int,float,double)
     strong  :对象类型,相当于MRC中的retain、
     copy   :     对象类型,且遵守了<NSCopying>协议
     weak、: 对象类型,但是内部不会对对象做retain的操作
     
 强引用strong,弱引用weak
     @property(retain,nonatomic) NSString *name;  //MRC下写法
     @property(strong,nonatomic) NSString *sex;     //ARC下写法-------强引用
     @property(weak,nonatomic)  NSArray *array; //weak-----------弱引用
     
6.2ARC与MRC的混编
需要对特定文件开启或关闭ARC,可以在工程选项中选择
Targets--->Compile phases  --->Compile Sources    在里面找打对应文件,添加 flag
     打开 ARC : -fobjc - arc
     关闭 ARC : -fno - objc - arc
     

     */
#pragma mark-----------------------------------------------------------------------------------------------------