天天看点

Objective-C初探

 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

    格式:

        @implementation OjbectName

        -(ReturnType) MethodName:(ParamType) ParamName LabelN:(ParamType) ParamName......{

            Statements;

            ......

        ......    ......    ......

        +(ReturnType) MethodName:(ParamType) ParamName LabelN:(ParamType) ParamName......{

    说明:

        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 ......;

        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){

        @finally{

内存管理:

    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");

继续阅读