objective-c,
objective-c,
Objective-C基础教程1-6章节
最近不算很忙,又没有太多深入研究,按照惯例找一些没接触过的新东西看看学习学习,WiEngine,Box2d之后,这次轮到了Objective-C。Objectvie-C随着苹果设备的风靡,也是最热门的技术之一,无奈之前对C一直存在一些芥蒂,所以没有去接触,不过怎么说语言也是共通的,有些坎肯定还是要迈过的,特别是当下所谓跨Android/iPhone平台,其实都是用C++在开发,所以上上手也是很有必要。
下面是对看Objective-C基础教程1-6章后,对一些东西的笔记,并不是完整的教程,只是类似拾遗,将一些不同的,不熟悉的东西记下来(和之前Python笔记类似)
一切都源于Hello World 恒古不变的定律,熟悉一门语言结构最快也就是这个万能的程序了,Objective-C扩展名为.m(之后书中也有提到.mm就是C++风格)
Objective-c代码
- #import <Foundation/Foundation.h>
- int main(int argc, const char *argv[]){
- NSLog(@"Hello Objective-C");
- return (0);
- }
其中NSLog方法是Objective-C专属的一种类型,所有cocoa的对象都被冠以了NS前缀,作为区分。传入的参数@""表示字符串作为NSString被处理,程序其余部分和C类似,#import的含义也不言而喻
布尔值
Objective-C中的布尔变量有些许小的不同,参数类型为BOOL,值为YES/NO,其中YES为1,NO为0,占8位
需要注意的是,如果将一个int,short这样的值赋给BOOL,只有低位字节会发挥作用,这是特别要注意的,因为这意味着,并不是传统认为的,非零即为true
Objective-C中有一种特有的语法:[对象 操作] 这在之后会一直看到
关于Objective-C中的OOP
@interface
至少目前我还将其于java中的接口相类比,名称也一样,但是有人告诉我Objective-C中的interface并不同于接口,而类似于接口的Objective-C中有一个叫做协议的东西,这个以后看到了我会再加以对比区分
Objective-c代码
- @interface Circle:NSObject
- {
- ShapeColor color;
- ShapeRect bounds;
- }
- -(void) setFillColor: (ShapeColor) color;
- -(void) setBounds: (ShapeRect) bounds;
- -(void) draw;
- @end
以上就是标准的一个@interface定义,应该很好理解,Circle含有2个变量color,bounds,拥有3个方法
特别注意方法的申明方式
(void) 表示返回类型 之后是方法名及参数
draw方法不含参数 也不用:
对于多个参数的方法申明
-(void) setTire: (Tire *) tire atIndex:(int) index;(这里的第二个参数看起来有些奇怪,但是在之后调用方法的过程中,atIndex会被用到)
Objective-C的方法调用使用了一种被称为中缀符的东西
看一下分别调用无参,1参和多参的语法
Objective-c代码
- [circle draw];
- [circle setFillColor:kRedColor];
- [car setTire:tire atIndex:2];<span> </span>
@implementation
与名字相同,实现,就是对@interface所申明内容的具体实现
Objective-c代码
- @implementation
- -(void) setFillColor:(ShapeColor c)
- {
- color=c;
- }
- @end
这里的color=c其实就相当于self.color=c(这里我又要做类比了,目前的认识self就相当于java中的this指针)
有了@interface和@implementation之后,我们对一个类(对象)的定义就算完成,那么如何实例化一个对象呢
Objective-c代码
- id shapes[3];
- shapes[0]=[Circle new];
- [shpaes[0] setBounds:rect];
- ...
这里又看到一个新的东西id,它是一种指向某个对象的指针,目前为止只是看到这一种用法,也没有太多认识,简单的被我理解成了索引
之后看到了new对象的方法[Circle new],再之后是调用对象的方法设置具体的参数
继承
Objective-c代码
- @interface Circle:Shape
很简单的方法,Objective-C在继承规则上于java,C#无异,不允许多重继承,不过既然有接口(或者应该叫协议),那么自然同java一样,达到相同的目的自然不难,同样的,子类可以调用父类的方法,通过super,比如[super setColor:c];
Ojbective-C中的空值为nil
接下来 来看一个Car是被如何自动构建的
Objective-c代码
- @implementation Car
- -(id) init
- {
- if(self=[super init]){
- engine=[Engine new];
- ...
- }
- return (self);
- }
这一段有些理解不能,在书中的注释中说到,这里指如果超类可以完成所需的一次性初始化,需要调用[super init]。init方法的返回值id描述了倍初始化的对象。将[super init]的结果赋给self是Objective-C的标准惯例。
Objective-C中一样有getter/setter方法,但是在命名规则上需要注意
Objective-c代码
- -(Engine *)engine;
- -(void) setEngine: (Engine *) engine;
在set方法中 依然采取setXXX的方式 但是get方法则直接采用XXX 而非getXXX,以免混淆
拆分
一般将@interface部分放入.h文件中
Objective-c代码
- #import <Cocoa/Cocoa.h>
- @interface Tire:NSObject
- @end
将其他部分放在.m中,在.m中记得引入该头文件
#import "Tire.h"
import下<>代表系统头文件 ""代表本地头文件
关键词@class 告诉编译器此处是一个类,还需要通过指针进行传递
Objective-c代码
- @class Tire
- @class Engine
- ...
- Engine *engine
注意这只有在通过指针指向其他类的情况下可用,减少编译器负担,在继承的情况下不可用,因为他需要了解超类的信息
----------------------------------------------
Foundation Kit
Cocoa由两个不同的框架组成 Foundation Kit和Application Kit
Foundation框架中有很多诸如NSString,NSArray等低级类和数据类型
Objective-c代码
- #import <Foundation/Foundation.h>
- int main(int argc, const char *argv[]){
- NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
- //insert code here...
- NSLog(@"Hello, World!");
- [pool drain];
- return 0;
- }
通过alloc创建并通过init初始化了一个池,在结尾处排空,这是Cocoa内存管理的预览
一些有用的数据类型
范围 NSRange
Objective-c代码
- typedef struct _NSRange{
- unsigned int location;
- unsigned int length;
- }NSRange;
表示相关事物的范围,如字符串中的字符范围或数组中的元素范围
创建一个新的NSRange有3种方式
Objective-c代码
- //1
- NSRange range;
- range.location=17;
- range.length=4;
- //2
- NSRange range={17,4};
- //3
- NSRange range=NSMakeRange(17,4);
第三种方法的好处是可以在任何能够使用函数的地方使用,比如当作参数
Objective-c代码
- [anObject flarbulateWithRange: NSMakeRange(13,15)];
几何数据类型 NSPoint,NSSize
Objective-c代码
- typedef struct _NSPoint{
- float x;
- float y;
- }NSPoint;
- typedef struct _NSSize{
- float width;
- float height;
- }NSSize;
比如Cocoa提供了矩形数据类型
Objective-c代码
- typedef struct _NSRect{
- NSPoint origin;
- NSSize size;
- }NSRect;
同样提供了NSMakePoint(),NSMakeSize(),NSMakeRect()方法
将这些数据类型作为struct而不是对象的好处是性能更高
字符串 NSString
创建字符串
Objective-c代码
- NSString *height;
- height=[NSString stringWithFormat: @"Your height is %d feet",5];
类方法
我们所创建的大部分方法是实例方法 用前导减号 - 声明
如果方法用于实现常规功能,用前导加好 + 来声明类方法
就如NSString的stringWithFormat方法
Objective-c代码
- + (id) stringWithFormat: (NSString *) format, ...;
关于大小
Objective-c代码
- - (unsigned int) length;
使用方式
Objective-c代码
- unsigned int length=[height length];
该方法可以正确处理国际字符串
比较
Objective-c代码
- isEqualToString
- - (BOOL) isEqualToString: (NSString *) aString;
使用方式
Objective-c代码
- NSString *thing1=@"hello 5";
- NSString *thing2;
- thing2=[NSString stringWithFormat: @"hello %d",5];
- if(thing1 isEqualToString: thing2]){
- NSLog(@"They are the same!");
- }
同样的compare方法
Objective-c代码
- - (NSCompar isonResult) compare: (NSString *) string;
返回一个NSComparisonResult枚举类型
Objective-c代码
- type enum _NSComparisonResult{
- NSOrderedAscending=-1,
- NSOrderedSame,
- NSOrderedDescending
- }NSComparisonResult;
如果返回NSOrderedAscending 表示左侧小于右侧 其他类似
不区分大小写的比较
Objective-c代码
- - (NSComparisonResult) compare: (NSString *) string
- options: (unsigned) mask;
options参数是一个掩码
NSCaseInsensitiveSearch 不区分大小写
NSLiteralSearch 完全比较,区分大小写
NSNumericSearch 比较字符个数而不是字符值 比如100应该排在99以后
Objective-c代码
- if([thing1 compare: thing2
- options: NSCaseInsensitiveSearch | NSNumericSearch] == NSOrderedSame){
- NSLog(@"They match");
- }
判断字符串内是否包含其他字符串
Objective-c代码
- - (BOOL) hasPrefix: (NSString *) aString;
- - (BOOL) hasSuffix: (NSString *) aString;
分别检查以特定字符串开头和结尾
Objective-c代码
- - (NSRange) rangeOfString: (NSString *) aString;
返回匹配的位置,如果找不到 则range.start=NSNotFound
可变性
NSString是不可变的
NSMutableString是可变字符串
两者间比较类似Java中的String和StringBuffer
创建NSMutableString的方法
Objective-c代码
- + (id) stringWithCapacity: (unsigned) capacity;
该容量只是一个建议
Objective-c代码
- NSMutableString *string;
- string = [NSMutableString stringWithCapacity: 42];
可以使用一些方法操作该string
Objective-c代码
- - (void) appendString: (NSString *) aString;
- - (void) appendFormat: (NSString *) format, ...;
使用起来非常方便 也很显而易见
Objective-c代码
- NSMutableString *string;
- string=[NSMutableString stringWithCapacity: 50];
- [string appendString: @"Hello here"];
- [string appendFormat: @"human %d!",39];
- //得到最后结果Hello here human 39!
类似的
删除字符串中的字符
Objective-c代码
- - (void) deleteCharactersInRange: (NSRange) range;
NSMutableString是NSString的子类,所以可以使用NSString的所有功能
因此同样可以使用stringWithFormat来创建NSMutableString
集合家族 NSArray NSDictionary等
NSArray可以放入任意类型的对象
两个限制:
1 只能存储Objective-C对象,而不能是C基础类型int,float,enum,struct等
2 不能存储零值nil NULL值
可以通过类方法arrayWithObjects创建,以逗号分割对象列表,并最后以nil表示列表结束
Ojbective-c代码
- NSArray *array;
- array=[NSArray arrayWithObjects: @"one",@"two",@"three",nil];
获得对象个数
Objective-c代码
- - (unsigned) count;
取得特定索引处对象
Objective-c代码
- - (id) objectAtIndex: (unsigned int) index;
例如遍历一个数组
Objective-c代码
- int i;
- for(i=0;i<[array count];i++){
- NSLog(@"index %d has %@",i,[array objectAtIndex: i]);
- }
将字符串切分成数组
Objective-c代码
- -componentsSeparatedByString
将数组合并成字符串
Objective-c代码
- -componentsJoinedByString
可变数组
NSArray是不可变的,类似的NSMutableArray可变
创建新的可变数组
Objective-c代码
- + (id) arrayWithCapacity: (unsigned) numItems;
在数组末尾添加对象
Objective-c代码
- - (void) addObject: (id) anObject;
删除特定位置对象
Objective-c代码
- - (void) removeObjectAtIndex: (unsigned) index;
枚举 NSEnumerator
通过objectEnumerator向数组请求枚举器
Objective-c代码- - (NSEnumerator *) objectEnumerator;
这似乎类似于Java的迭代器Iterator
使用
Objective-c代码
- NSEnumerator *enumerator;
- enumerator=[array objectEnumerator];
可以从后向前浏览集合 reverseObjectEnumerator
请求下一个对象
Objective-c代码
- - (id) nextObject;
当返回nil时表示结束
快速枚举
Objective-c代码
- for(NSString *string in array){
- NSLog(@"I found %@",string);
- }
NSDictionary 有些类似于Map(散列表,关联数组)
类似的NSDictionary不可变,可变的NSMutableDictionary
创建字典的方法
Objective-c代码
- + (id) dictionaryWithObjectsAndKeys: (id) firstObject, ...;
例如
Objective-c代码
- Tire *t1=[Tire new];
- Tire *t2=[Tire new];
- Tire *t3=[Tire new];
- Tire *t4=[Tire new];
- NSDictionary *tires;
- tires=[NSDictionary dictionaryWithObjectsAndKeys: t1, @"front=left", t2, @"front-right", t3, @"back-left", t4, @"back-right", nil];
使用objectForKey来获取值
Objective-c代码
- - (id) objectForKey: (id) aKey;
例如查找右后轮胎
Objective-c代码
- Tire *tire=[tires objectForKey: @"back-right"];
同样的,对于可变的字典
Objective-c代码
- + (id) dictionaryWithCapacity: (unsigned int) numItems;
为可变字典添加元素
Objective-c代码
- - (void) setObject: (id) anObject forKey: (id) aKey;
如果当前已有值,则新值会替代原有的值
删除值
Objective-c代码
- - (void) removeObjectForKey: (id) aKey;
使用但不扩展
不要自己去创建NSString,NSArray,NSDictionary的子类
各种数值
就和Java中对int,float等有Integer,Float等对象封装,Objectvie-C也提供了NSNumber的包装类
Objective-c代码
- + (NSNumber *) numberWithChar: (char) value;
- + (NSNumber *) numberWithInt: (int) value;
- + (NSNumber *) numberWithFloat: (float) value;
- + (NSNumber *) numberWithBool: (BOOL) value;
类似的还有long,long long等
例如将一个包装后的数据放入数组
Objective-c代码
- NSNumber *number;
- number=[NSNumber numberWithInt: 42];
- [array addObject: number];
- [dictionary setObject: num forKey: @"Bork"];
从包装类获取值
Objective-c代码- - (char) charValue;
- - (int) intValue;
- - (NSString *) stringValue;
等
NSValue
NSNumber是NSValue的子类,NSValue可以包装任意值
Objective-c代码
- + (NSValue *) valuseWithBytes: (const void *) value
- objCType: (const char *) type;
例如,将NSRect放入NSArray
Objective-c代码
- NSRect rect=NSMakeRect(1,2,3,4);
- NSValue *value;
- value=[NSValue valueWithBytes: &rect
- objCType: @encode(NSRect)];
- [array addObject: value];
这里使用@encode编译器指令,它可以接受数据类型的名称并转化为合适的字符串
使用getValue取值
Objective-c代码
- - (void) getValue: (void *) value;
传递的是存储该数值的变量地址
Objective-c代码
- value=[array objectAtIndex: 0];
- [value getValue: &rect];
Cocoa提供了常用的将struct型数据转换成NSValue的方法
Objective-c代码
- + (NSValue *) valueWithPoint: (NSPoint) point;
- + (NSValue *) valueWithSize: (NSSize) size;
- + (NSValue *) valueWithRect: (NSRect) rect;
Objective-c代码
- - (NSPoint) pointValue;
- - (NSSize) sizeValue;
- - (NSRect) rectValue;
例如,在NSArray中存储和检索NSRect
Objective-c代码
- value=[NSValue valueWithRect: rect];
- [array addObject: value];
- ...
- NSRect anotherRect=[value rectValue];
NSNull
之前提到nil在NSArray和NSDictionary中有特殊的含义,所以不能把nil放入其中,如果要真的表示没有,Objectvie-C提供了NSNull
使用[NSNull null]==来比较是否为空
--------------------------------------------------------
完全是按照书上章节的顺序来的 这次是第九章的内容 关于内存管理
作为一名一直写java,当初就是因为java的自动垃圾回收机制,于是偷懒投奔java阵营的来说,这次不得不又回过头来面对这个问题了。后面的笔记只是对书中一些内容的记录总结,由于没有实战,具体使用中会碰到什么问题还是不得而知,而且我想那一定会存在相当多的问题,好在最后给出的三条准则还是非常易用的。(听同伴说xCode提供了检查内存泄露的工具,挺好用)
本章最后提到了Objective-C也同样可以打开垃圾回收,不过由于只对高版本有效,并非通用,所以个人感觉既然使用了Objective-C,因此还是应该掌握内存管理的方法。
对象的声明周期:
诞生(通过alloc或new)、实现(接收消息和执行操作)、交友(借助方法的组合和参数)、死去(被释放)
Cocoa使用引用计数
当使用alloc,new或者copy方法创建一个对象时,计数器值设为1
发送retain消息增加计数器值,减少使用release
当计数器归0,Objective-C自动发送dealloc消息,可以重写dealloc方法,但是不要直接去调用该方法
发送retainCount消息获得当前计数器值
Objective-c代码
- - (id) retain;
- - (void) release;
- - (unsigned) retainCount;
Objective-c代码
- [[car retain] setTire:tire at Index:2];
表示要求car对象将计数器加1,并执行setTire操作
一种set方法的正确内存管理方法
Objective-c代码
- - (void) setEngine: (Engine *) newEngine{
- [newEngine retain];
- [engine release];
- engine=newEngine;
- }
自动释放池
NSObject类提供了autorelease方法
Objective-c代码
- - (id) autorelease;
执行后对象将被添加到自动释放池中,自动释放池被销毁时,向其中所有对象发送release消息
Cocoa内存管理规则
* 当使用new,alloc,copy方法创建一个对象时,该对象保留计数器为1,如果不再使用该对象,需要手动发送release或autorelease消息
* 通过其他方式获得的对象,则假设该对象计数器为1,并以设置自动释放,不需要做任何事,如果需要在一段时间内使用,那么保留该对象并确保在工作完成后释放
* 如果保留了某个对象,最终需要手动释放该对象,保持retain和release使用次数相等
例如
临时对象
Objective-c代码
- NSMutableArray *array;
- array=[[NSMutableArray alloc] init];
- //...use array...
- [array release];
使用了alloc获得对象,所以用完需要释放
Objective-c代码
- NSMutableArray *array;
- array=[NSMutableArray arrayWithCapacity:17];
- //use it, autorelease
注意这里使用了arrayWithCapacity获得对象,并不是3者之一,所以无需做任何事
Objective-c代码
- NSColor *color;
- color=[NSColor blueColor];
和上述情况相同,其实这里的blueColor是一个全局单例对象,永远不会被销毁
拥有对象
Objective-c代码
- - (void) doStuff{
- //flonkArray is an instance variable
- flonkArray=[NSMutableArray new];
- }
- - (void) dealloc{
- [flonkArray release];
- [super dealloc];
- }
Objective-c代码
- - (void) doStuff{
- //flonkArray is an instance variable
- flonkArray=[NSMutableArray arrayWithCapacity: 17];
- [flonkArray retain];
- }
- - (void) dealloc{
- [flonkArray release];
- [super dealloc];
- }
相关文章
- 暂无相关文章
用户评论