Objective-C 基于C 语言的,增加面向对象的相关特性。

NextStep是一个使用Objective-C编写的功能强大的工具包,里面包含大量的类库、结构体等,被APPLE收购后更名为Cocoa,但APPLE并未更改NextStep中的类库名,所以存在大量以NS为前缀的类名、结构体、枚举等;

Cocoa框架由Foundation Kit、App Kit两部分组成;

    Foundation Kit:基础工具库;
    App Kit:UI库、高级对象等;

GNUStep调试Objective-C:

    gcc $(FileName) -o $(FileNameNoExt).exe 
        -I D:\Libraries\Apple\GNUstep\System\Library\Headers 
        -L D:\Libraries\Apple\GNUstep\System\Library\Libraries 
        -lobjc -lgnustep-base -fconstant-string-class=NSConstantString
    有多个需要编译的源文件时,各文件间用空格隔开;
    -I:头文件查找路径;
    -L:库文件查找路径;
    -l:需要连接的库文件;
    -fconstant-string-class=NSConstantString:常量字符串所使用的类;

数据类型:

    BOOL:不是对象类型,使用8位(一个字节)的整数进行表示,对于二进制表示大于8位的数据,取其低8位有效。只有YES和NO两个值(不是TRUE/FALSE);
    nil:空。nil可以回应消息,因此不必为空指针而烦恼;
    NSString:字符串。@"..."是字符串自面值的表示方式;
    class:本身以为指针,故该类型的变量前不需要*;
    id:泛型对象,可以表示任意类型的Objectiv-C对象。是一个结构体指针,其内部通过Class类型的isa指向了继承了NSObject的对象,故该类型变量前不需要*;
    SEL:类型选择器,用于表示Objective-C的一个方法,而且是一个已存在的方法,类似于C中的函数指针。通过@selector(MethodName)获取。由于本身已是指针,故不需要*;
    NSString:字符串,字面值用@"......"表示;
        NSString *StrName=[[NSString alloc] initWithString:@StrValue]:使用NSString字面值初始化NSString对象;
        NSString *StrName=[[NSString alloc] initWithCString:strCalue]:使用C字符串初始化NSString对象;
        +(NSString*) stringWithFormat:@"......",......:用格式化模版个时候字符串;
        -(BOOL) isEqualToString:(NSString*) StrName:比较两个字符串是否相等。==比较指针,对象比较用equal方法;
        -(NSComparisonResult) compare:(NSString*) StrName options:(NSStringCompareOptions) Options:详细比较两个字符串时候相等,如是否忽略大小写等。
            返回值为enum类型,如NSOrderdSame表示相等。NSStringCompareOptions也是enum类型,常用的值有NSCaseInsensitiveSearch,NSNumericSearch,分别表示忽略大小写和字说相等。
            由于NSStringCompareOptions的枚举值都是2的指数,所以可以用位运算操作,如:NSCaseInsensitiveSearch|NSNumericSearch,表示忽略大小并且字数相等;
        -(BOOL) hasPrefix:(NSString) ParamName:判断字符串是否以ParamName作为前缀。hasSufix判断后缀;
        -(NSRange) rangeOfString:(NSString*) ParamName:判断是否包含参数ParamName。返回值为结构体,如果包含,其location为包含字符串ParamName所在的起始位置,length为长度。
            如果不包含,location为NSNotFound,length为0;
        componentsSeparatedByString:(NSString*) Separator:按照给定的字符串Separator将字符串分割为数组;
        length:返回字符串长度;
    NSMutableString:继承自NSString长度可变的字符串。NSMutableString一般使用类方法;
        +(NSMutableString*) stringWithCapacity:(int) Capacity:创建NSMutableString,Capacity指定预先分配的字符串长度;
        -(NSMutableString*) appendString:(NSString*) StrName:在原字符串后追加内容;
        -(void) deleteCharactersInRange:(NSRange) RangeName:删除指定范围内的字符串,常与rangeOfString方法联用;
    NSArray:数组,nil表示数组元素的结束。不能存储基本数据类型、enum、structur、nil,只能存储Objectiv-C的对象;
        count:返回数组元素个数;
        objectAtIndex:(int) idx:返回指定索引位置的数组元素;
        componentsJoinedByString:(NSString*) Joinor:按照给定的连接字符串Joinor将数组连接为字符串;
    NSMutableArray:长度可变的数组;
        +(NSMutableArray) arrayWithCapacity:(int) Capacity:创建长度为Capacity的数组;
        -(id) objectAtIndex:(int) Idx:返回NSMutableArray中指定索引位置中的元素;
        addObject:(id) ObjectName:在数组的末尾添加对象;
        removeObjectAtIndex:(int) Idx:移除数组中指定索引位置的元素;
        componentsJoinedByString:(NSString*) Joinor:同NSArray的componentsJoinedByString一样,按照指定的字符串拼将数组拼接为字符串;
        objectEnumerator:获取反转之后的数组迭代器,为NSEnumerator类型。NSEnumerator中的nextObject方法获取迭代器当前位置的下一个元素。使用迭代器时,不能对数组进行添加、删除操作;
    NSDictionary:字典(哈希表),用于存储key-value的数据结构。与Java中Map类似;
        +(NSDictionary) dictionaryWithObjectsAndKeys:(NSObject*) ValueN,(NSObject*) KeyN, ...... ,nil:以可变参数创建NSDictionary对象。可变参数中每两个参数组成一个value-key对,以nil表示结束;
        -(NSObject*) objectForKey:(NSObject*) Key:按照指定可key查找对应的alue;
        -(NSObject*) setObject:(NSObject*) Value forKey:(NSObject*) Key:向NSDictionary中添加key-value对;
        -(void) removeObjectForKey:(NSObject*) Key:移除NSDictionary对象中指定key的alue;
        -(NSEnumerator*) keyEnumerator:获取key的枚举器;
    NSSet:哈希Set,表示以hash方式计算存储为的集合,与Java中HashSet一致。NSSet中的每个对象都有一个唯一的hash值,重复的对象只能保留一个,因此引出对象比较的问题,
        需要实现从NSObject继承而来的两个方法,即-(BOOL) isEqual:(id) ObjectName和-(NSUInteger) hash。与Java一样,两个相同的对象必须有相同的hashCode,所以这两个方法必须同时实现;
        +(NSSet*) setWithObjects:(id) Object,(id) ObjectN,......,nil:创建NSSet对象;
        -(NSEnumerator*) objectEnumerator:获取NSSet迭代器;
    NSMutableSet:长度可变的哈希Set;
    NSValue:封装类。对于以上几种容器,所操作的数据都是对象,对于基本数据类型,enum,struct,nil不适用,所以需要对其封装;
        +(NSValue*) valueWithBytes:(VarPointer) VarName,objCType:@encode(VarType):将类型为VarType的变量Varname封装为对象。
            其中第一个参数为所要封装的数据的地址,第二个参数为描述数据累i系那个、大小的字符串,并用@encode指令包装数据所属的类型;
        -(void) getValue:(void*) Value:取出NSValue中中的数据内容。参数为一指针,getValue将传入的指针指向所存储的数据。一般Cocoa中getXX方法都是这个作用,所以类中的getter方法不以get作为前缀;
    NSNumber:NSValue的子类,用于封装基本数据类型,如int,char,float,BOOL等;
        +(NSNumber) numberWithChar:(char) ChrName:封装char类型基础数据;
        +(NSNumber) numberWithInt:(int) IntName:封装int类型基础数据;
        +(NSNumber) numberWithFloat:(float) FltName:封装float类型基础数据;
        +(NSNumber) num,berWithBool:(BOOL) BolName:封装BOOL类型基础数据;
    NSNull:将存储控制到集合类;
        +(NSNull) null:创建NSNull对象;
    NSDate:日期类型;
        +(NSDate) date:以当前日期创建NSDate对象;
        +(NSDate) dateWithTimeIntervalSinceNow:(int) TimeSpan:返回与当前时间相比,相差TimeSpan时刻的日期对象。TimeSpan可为负值;
        +(NSCalendarDate) dateWithString:(NSString*) StrDate calendarFormat:(NSString*) DateFamat:以指定的格式将字符串转化为NSClendarDate对象;
            格式化字符串:
                %Y:四位数的年
                %y:两位数的年
                %B:月份的英文全些
                %b:月份的英文简写
                %m:两位数月份
                %A:星期的英文全些
                %a:星期的英文简写
                %d:两位说日期
                %H:24小时制的两位数小时
                %l:12小时制的两位数小时
                %p:显示A.M或P.M
                %M:两位数的分钟
                %S:两位数的秒
                %F:三位说的毫秒
                %Z:显示时区的名字
                %z:显示时区与标准时区的偏移时间 HHMM
    NSData:数据缓冲区,类似于Java中字节数组;
        +(NSData*) dataWithBytes:(const void*) Bytes length:(NSUinteger) length:第一个参数为所要缓冲数据的起始位置,第二个参数指定数据的长度;
    NSMutableData:长度可变的数据缓冲区;
    NSAutoreleasePool:未知

类的声明:ClassName.h

    Objective-C类的定义前必须先定义一个接口,该接口用于描述这个类的组成,包括成员变量,类变量,类方法,成员方法。接口的扩展名为.h,也就是C/C++中的头文件。

    格式:
        #import Header
        static VarType VarName;
        @interface InterfaceName:SupperName{
            AccessModeifers VarType VarName;
            …………
        }
        -(ReturnType) MethodName:(ParamType) ParamName LabN:(ParamType) ParamName …………
        …………
        +(ReturnType) MethodName:(ParamType) ParamName LabN:(ParamType) ParamName …………
        …………
        @end
        说明:
            1.import:导入头文件。与C一样的是,如果希望从当前目录中查找头文件,
                找不到就到系统的头文件库中查找,对头文件使用双引号(""),
                如果只想从系统头文件库中查找,对头文件使用单书名号(<>)。
                GNUStep中Objective-C的Foundation头文件目录为:@\GNUstep\System\Library\Headers\Foundation
                GNUStep中Objective-C的AppKit头文件目录为:@\GNUstep\System\Library\Headers\AppKit
            2.static:标识的类变量定义在接口的外面,类变量只能本类访问,除非提供类方法给外部访问这个类变量;
            3.@+指令:C之外的Objective-C的衍生语法。@interface表示定义一个接口,接口名后紧跟一个冒号,冒号后是父类名。
                Objective-C的顶级父类是NSObject;
            4.成员变量:定义在接口内部({}中)。与Java中成员变量同一概念。使用@public,@protected,@private
                作为访问修饰符。默认@protected。Objective-C中只有成员变量有访问修饰符,类变量,类方法,成员方法是没有访问修饰符的。
                所有的方法都是public的,所有的类变量都是私有的;
            5.成员方法和类方法:-开头的方法为成员方法,+开头的方法为类方法。
                方法中的类型描述(返回值类型,参数类型)都必须用括号()包围。
                如果方法中有多个参数,每个参数都有一个标签名(可以省略,但不建议),
                每个标签名后使用冒号与参数类型描述分隔。类方法通常用来提供初始化对象的便捷方法,
                且只能由类调用,使用对象调用时会报错;
            6.@end:标示接口定义的结束。由于{}只能放置成员变量,因此必须有个结束标志;
            7.Objective-C中的@interface与Java中的interface不是同一概念。而@protocol与Java中的interface一样。
                @interface只是类的描述,通常在独立的h文件中,可以理解为C中的函数原型,也就是在Objective-C中应叫类原型,
                通过这个接口,编译器可以知道具体实现类有哪些功能;
            8.setter和getter:Objective-C中以get作为前缀的方法具有特殊的作用,故不能用于getter方法;

类的实现:ClassName.m

    格式:
        #import Header
        @implementation OjbectName
        -(ReturnType) MethodName:(ParamType) ParamName LabelN:(ParamType) ParamName......{
            Statements;
            ......
        }
        ......    ......    ......
        +(ReturnType) MethodName:(ParamType) ParamName LabelN:(ParamType) ParamName......{
            Statements;
            ......
        }
        ......    ......    ......
        @end
    说明:
        1.该类的任务是实现所引用Header中@interface里的方法,因此不能在这里定义类变量或成员变量;
        2.在此不必实现@interface中所有方法,也可在此定义@interface中没有声明的方法(因为Objectiv-C是动态语言);
        3.当参数名与类属性名一样时,self->PropertyName指类中属性,同Java中this.PropertyName;
        4.[supper MethodName:(ParamType)ParamValue LabelN:(ParamType) ParamValue ......]:调用父类中的指定方法,如:self=[supper init];
        4.[self MethodName:(ParamType)ParamValue LabelN:(ParamType) ParamValue ......]:调用自身方法;

Category:

    类别,用于在不使用继承方式下扩充一个类的功能。一个类可以有多个类别;
    实现:在想要扩展的@interface的名字后加(CategoryName),括号内是类别的名字,这个名字必须是唯一的,相应的实现类@implementation的名字后也要加相同的(CategoryName);
    类别与继承的区别:不能定义新的成员变量,如果新方法与原始类中的方法同名,原始方法将被隐藏,不能使用super激活原始类中的同名方法;

协议:ProtocolName.h

    实现:
        @protocol ProtocolName
            -(ReturnType) MethodName:(ParamType) ParamValue LabelN:(ParamType) ParamName ......;
        @end
    说明:
        1.协议在Objectiv-C中的作用等同于Java中的接口,切允许多继承;
        2.协议的实现:ClassName <ProtocolName,ProtocolN,......>;
        3.协议类型:<ProtocolName> Val,同id<ProtocolName> Val,相当于Java中使用接口类型作为对象;

        4.id<ProtocolName,ProtocolNameN,......>:以PotocolNameN作为泛型参数,以明确的告知想把id作为某些协议使用。也可不写泛型参数;

类操作:

    1.创建对象:
        ClassName *ObjectName[[ClassName alloc] init];
        Objective-C中实例只能用指针作为变量;
        创建对象分两个步骤实现:分配内存[alloc]和初始化[init];
        alloc:从NSObject继承而来的类方法,用于给对象分配存储空间。所有的成员变量在此时确定了自己的内存位置,并被赋默认值(INT:0/FLOAT:0.0/BOOL:NO/OBJECT:NIL)并返回对象的指针;
        init:从NSObject继承而来的成员方法,可以定制自己的init方法。Objective-C对init方法没有特殊的要求,就是一个普通方法而已,只是习惯以init作为前缀,一般都返回当前类型的指针或id类型;
    2.调用实例方法:
        [ObjectPointer MethodName:ParamValue LabelN:ParamValue ......];
    3.调用类方法:
        [ClassPointer MethodName:ParamValue LabelN:ParamValue ......];
        或:
        [[ClassName class] MethodName:ParamValue LabelN:ParamValue ......];
        或:
        Class name=[ClassName class];//因Class已是指针,故name前不需要*;
        [name MethodName:ParamValue LabelN:ParamValue]
    4.使用@public/@protected成员变量:
        OjbectName->PropertyName;
    5.获取Class的几种方法:
        [Class/Object class];
        [Class/Object superclass];
        NSClassFromString(StrClass/StrObject);

异常:

    Object-C异常都继承自NSException;
    Object-C异常处理:创建NSException异常对象并抛出即可;
    创建异常对象:
        NSException * excp=[ExceptionClass exceptionWithName:@"Name" reason:@"reason" userInfo:nil];
    抛出异常:
        @throw excp;
    捕获异常:
        @try{
            //Statments;
        }
        @catch(NSException *excp){
            //Statments;
        }
        @finally{
            //Statments;
        }

内存管理:

    Objectiv-C即支持手动管理内存,也支持GC机制,但GC机制仅对MAC OS X有效,对IOS设备无效;
    Objective-C在使用alloc,new,copy时为对象分配内存,然后返回所分配的内存的首地址,存入指针变量。使用dealloc释放内存。new是alloc和init的合写形式;
    Objective-C回收内存是通过一个计数器retainCount来表示有多少个地方在引用当前对象。一个对象在被alloc后其retainCount为1,之后每次调用retain方法都会使retainCount加1,
        调用release使retainCount减1。当Objectiv-C发现一个对象的retainCount为0时,就会立即调用其从NSObject继承而来的dealloc方法回收内存。该调用动作由Objectiv-C运行环境完成;
    内存释放:
        [ObjectPointer release];

对象复制:

    对象能否被复制的依据是判断该对象是否遵循NSCopying协议。该协议中有个复制方法:
        -(id) copyWithZone:(NSZone*) Zone:该方法的调用是由Objecti-C的运行环境来完成的,程序中使用copy方法实现对象的调用。Zone是由系统传进来的一个表示内存空间的NSZone对象,即在该空间内复制原来的对象。复制过程如下:
            1.调用类方法allocWithZone传入的NSZone参数,为即将产生的新对象分配空间,该方法必须由[self class]调用;
            2.调用初始化方法,完成新实例的创建;
            3.把原有实例中的内容都setter到新实例中;
            ClassName.m实现:
                -(id) copyWithZone:(NSZone*) zone{
                    ClassName *obj=[[[self class] allocWithZone:zone] init];
                    return obj;
                }

多线程:

    Objective-C的多线程与Java相似,分为原始的线程操作和线程池两种。线程池是使用队列等机制对原始线程的封装;
    NSThread:NSThread类型表示线程,其对象的创建如下:
        -(id) init:
        -(id) initWithTarget:(id) Target selector:(SEL) Selector object:(id) Argument:第一个参数指定目标对象,一般情况下是当前的实例self。
            第二个参数指要运行的方法,相当于Java中的run方法。第三个参数一般为nil;
        -(void) detachNewThreadSelector:(SEL) Selector toTarget:(id) Target withObject:(id) Argument:该方法与initWithTarget一样,区别就是不需要显示的released这个线程,因为么有使用alloc;
    -(void) setName:(NSString*) ThreadName:对线程设置名称;
    -(void) start:启动一个线程;
    -(void) exit:结束一个线程。使用该方法前要先将其引用计数器归0;
    +(void) sleepForTimeInterval:(int) TimeSpan:使当前线程暂停指定时间;
    +(id) currentThread:获取当前正在运行的线程;
    -(NSString*) name:获取当前线程的名字;
    NSCondition:执行同步操作,功能和用法上相当于Java中的Lock对象。一段代码如果需要同步就用NSCondation先锁定,需要同步的部分执行完毕再解锁。
        NSCondition对象的两个方法lock和unlock分别进行枷锁和解锁操作,将同步执行的代码放于这两个方法之间即可;
        此外Objective-C支持@synchronized指令做代码同步:
        @synchronized(ObjectToLock){
            //Statements;同步代码
        }
    与主线程交互:
        子线程不能直接与主线程交互,需要在子线程run方法中调用performSelectorOnMainThread才能实现:
        -(void) performSelectorOnMainThread:(SEL) Selector withObject:(id) Arg waitUntilDone:(BOOL) Wait;
    线程池:
        Objectiv-C使用NSOperation和NSOperationQueue两个类实现线程池的操作。NSOperation与Java中Runnable相似,其中的main方法就是要执行的操作。
        NSOperationQueue是个线程池队列。当把NSoperation添加到NSOperationQueue中时,队列就会先对NSOperation进行remain操作,然后再执行其中的线程操作。
            默认情况下队列中的任务串行执行,当NSOperation中的isConcurrent方法返回YES时,队列中的任务就可以并行执行;
            -(void) setMaxConcurrentOperationCount:(int) Count:设置线程池做大可同时执行的操作数;
            -(void) addOperation:(NSOperation*) Option:将任务添加到线程池中;

KVC && KVO:

    KVC是NSKeyValueCoding的缩写,是Foundation Kit中NSObject的一个Category,作用是提供动态访问对象中的属性,类似Java中的反射机制;
    KVC使用了与NSDicionary相似的key-value的操作方法,即按照按照一个字符串key在对象中查找属性,然后获取或设置其值。如果key为XXX,对于获取属性值的查找规则如下:
        1.查找.h文件中声明的成员方法getXXX或XXX;
        2.查找.m文件中声明的变量是有成员方法_getXXX或_XXX;
        3.查找成员变脸_XXX或XXX;
        如getter和setter:
            正常情况:
                [Obj setter:(id) Value];//setter
                NSLog(@"%@",[Obj getter]);//getter
            KVC中:
                [Obj setValue:(id) Value forKey:(id) Property];//setter
                NSLog(@"%@",[Obj valueForKey:(id) Property];//getter
    KVC一般用于动态绑定,即才运行时确定调用哪个方法。在解析key的字符串时会比正常的setter,getter慢,而且编译器无法在编译时对方法调用作出检查;
    KVO是NSKeyValueObserving的缩写,基于KVC和观察者模式实现的一种通知机制。可以类比Java中的JMS,通过定于的方式,实现两个对象间的解耦,但又可以让它们相互调用。
        按照观察者模式的订阅机制,KVO必须有如下三个方法:
        订阅:Subscribe
            -(void) anddObserver:(NSObject*) Observer forKeyPath:(NSString*) Path options:(NSKeyValueObservingOptions) Options context:(void*) Context:
                Options为NSKeyValueObservingOptionOld,NSKeyValueObservingOptionNew;
        取消订阅:Unsubxcribe
            -(void) removeObserver:(NSObject*) Observer forKeyPath:(NSString*) Path;
        接收通知:Receive Notification
            -(void) observeValueForKeyPath:(NSString*) Path ofObject:(id) Object change:(NSDictionary*) Change context:(void*) Context;
    Notification是Objective-C中的另外一种事件通知机制。

NSPredicate:

    Cocoa提供NSPredicate谓词,用于指定过滤条件。谓词是指在计算机中表示计算真假值的函数,像SQL中的查询条件,主要用用从集合中分检出符合条件的对象,也可用于字符串的正则匹配;
    +(NSPredicate*) predicateWithFormat:(NSString*) Format:获取满足条件的对象集合。参数Format和SQL中where语句相似,也可用NSLog的格式化输出模版;
    -(BOOL) evaluateWithObject:(id) Object:判断对象Object是否满足NSPredicate对象的过滤条件;
    相关:
        1.逻辑运算符:AND、OR、NOT:
            计算并、或、非的结果;
        2.范围运算符:BETWEEN、IN:
            @"pId BETWEEN{1,5}";
            @"name IN {'nme1','nme2'}";
        3.占位符:
            NSPredicate *pdtTmp=[NSPredicate predicateWithFormat:@"name==$NAME"];
            NSDicionary *dcr=[NSDicionary dictionaryWithObjectsAndKeys:@"Name1",@"NAME",nil];
            NSPredicate *pdt=[pdtTmp predicateWithSubstitutionVariables:dic];
            该例中的占位符就是字典对象中的key,可以使用多个占位符,只要key不同就可以了;
        4.快速筛选数组:
            NSPredicate *pdt=[NSPredicate pridicateWithFormat:@"pId>1"];
            NSMutableArray *aryPdt=[aryObj filteredArrayUsingPredicate:pdt];
            aryPdt为从数组aryObj中筛选的满足pdt的元素所组成的新数组;
        5.字符串运算符:
            BEGINSWITH、ENDSWITH、CONTAINS:分别表示是否以某字符串开头、结束、和包含。它们可以与c、d联用,表示是否忽略大小写、是否忽略重音字母;
            @"name BEGINSWITH[cd] 'HE'":判断name是否以He开头,并忽略大小写和重音;
        6.LIKE:
            使用?表示一个字符,*表示多个字符。也可以与c、d联用;
            @"name LIKE '???er'":与Paper Plane匹配;
        7.SELF:
            适用于所匹配的数组元素为字符串或其它没有属性的类型,而非对象;
            NSArray *ary=[NSArray arrayWithObjects:@"Apple",@"Google",@"Microsoft",nil];
            NSPredicate *pdt=[NSPredicate predicateWithFormat:@"SELF=='Apple'"];
        8.正则表达式
            NSPredicate使用MATCHES匹配正则表达式,
            NSString *rgx=@"^A.+e$";
            NSPredicate *pdt=[NSPredicate predicateWithFormat:@"SELF MATCHES %@",rgx];
            if([pdt evaluateWithObject:@"Apple"]){
                printf("YES\n");
            }
            else{
                printf("NO\n");
            }