CG@CPPBLOG

/*=========================================*/
随笔 - 76, 文章 - 39, 评论 - 137, 引用 - 0
数据加载中……

用OBJC编程 6 - Value and Collections

用OBJC编程 6 - Value and Collections

OBJC里可以用基本的C原生类型,也定义了一些扩展的原生类型。
BOOL类型,它的值是YES和NO,YES等于true等于1。NO等于false等于0。
Cocoa定义了特殊的原生类型,如NSInteger和CGFloat。像NSInteger和NSUInteger,依赖于平台,在32位系统下是32位的,在64位下是64位的。
通过API传递时,最佳实践是使用这些特定平台的类型。而局部变量如循环计数,使用基本C变量更好。

C结构体可持有原生类型
一些Cocoa API用C结构体持有数值
NSString *mainString = @"This is a long string";
NSRange substringRange = [mainString rangeOfString:@"long"];
NSRange结构体持有location和length,本例中,substringRange为{10,4}。
类似的在Quartz中,基于CGFloat,NSPoint和NSSize(OSX)或者CGPoint和CGSize(IOS)都是C结构体。

用对象来代替原生类型

例如NSString,NSString是不可变的,这意味着你需要一个不同的字符串时,你需要创建一个新的对象。NSMutableString是可变的,是NSString的子类。
NSString *firstString = [[NSString alloc] initWithCString:"Hello World" encoding:NSUTF8StringEncoding];
NSString *secondString = [NSString stringWithCString:"Hello World" encoding:NSUTF8StringEncoding];
NSString *thirdString = @"Hello World";

// ------------
NSString *name = @"John";
name = [name stringByAppendingString:@"ny"]; // returns a new string object

//----------------
NSMutableString *name = [NSMutableString stringWithString:@"John"];
[name appendString:@"ny"]; // same object, but now represents "Johnny"

格式化字符串
NSString *magicString = [NSString stringWithFormat:@"The magic number is %i", magicNumber];

NSNumber可以表示任何基本C标量类型,包括,char, double, float, int, long, short, 以及unsigned类型和BOOL。
NSNumber* magicNumber     = [[NSNumber alloc] initWithInt:42];
NSNumber* unsignedNumber  = [[NSNumber alloc] initWithUnsignedInt:42u];
NSNumber* longNumber      = [[NSNumber alloc] initWithLong:42l];
NSNumber* boolNumber      = [[NSNumber alloc] initWithBOOL:YES];

NSNumber* simpleFloat  = [NSNumber numberWithFloat:3.14f];
NSNumber* betterDouble = [NSNumber numberWithDouble:3.1415926535];

NSNumber* someChar = [NSNumber numberWithChar:'T'];

可以使用字面常量来创建NSNumber实例,这些例子等价于使用NSNumber的工厂方法
NSNumber *magicNumber = @42;
NSNumber *unsignedNumber = @42u;
NSNumber *longNumber = @42l;
NSNumber *boolNumber = @YES;
NSNumber *simpleFloat = @3.14f;
NSNumber *betterDouble = @3.1415926535;
NSNumber *someChar = @'T';

可以使用访问器获得标量值
int scalarMagic = [magicNumber intValue];
unsigned int scalarUnsigned = [unsignedNumber unsignedIntValue];
BOOL scalarBool = [boolNumber boolValue];

NSNumber也可以用在NSInteger和NSUInteger上面
NSInteger anInteger = 64;
NSUInteger anUnsignedInteger = 100;

NSNumber *firstInteger = [[NSNumber alloc] initWithInteger:anInteger];
NSNumber *sencondInteger = [NSNumber numberWithUnsignedInteger:anUnsignedIneger];

NSInteger integerCheck = [firstInteger integerValue];
NSUInteger unsignedCheck = [sencondInteger unsignedIntegerValue];

NSNumber实例是不可变的,而且没有可变版本的子类,如果你需要一个不同的数字,就使用另一个NSNumber实例。NSNumber实际是一个类簇class cluster。

使用NSValue,NSValue是NSNumber的父类,可以用来持有更多的类型,包括指针和结构等。它有非常多的工厂方法。
NSString *mainString = @"This is a long string";
NSRange substringRange = [mainString rangeOfString:@"long"];
NSValue *rangeValue = [NSValue valueWithRange:substringRange];

// ---------
typedef struct{
    
int i;
    
float f;
} MyIntegerFloatStruct;

//======================
stuct MyIntegerFloatStruct aStruct;
aStruct.i = 42;
aStruct.f = 3.14;

NSValue *structValue = [NSValue value:&aStruct withObjCType:@encode(MyIntegerFloatStruct)];

Collections 容器
像NSArray,NSSet和NSDictionary这些容器可以管理一组OBJC 对象实例,如果你要放一个标量进去,需要包装为NSNumber或者NSValue。这些容器使用强引用持有它们的内容,也就意味着这些对象实例和容器生命周期一样。
基本的NSArray,NSSet和NSDictionary都是不可变的,它们都有一个可变版本的子类。

NSArray是有序的容器,它的内容不必是同一类对象。它有很多不同的初始化方法和工厂方法,依赖于对象的数目:
+ (id)arrayWithObject:(id)anObject;
+ (id)arrayWithObjects:(id)firstObject, ,,,;
+ (id)initWithObjects: (id)firstObject, ,,,;

可变参数版本的如arrayWithObjects依赖nil终止
NSArray *someArray = [NSArray arrayWithObjects:someObject, someString, someNumber, nil];

如果某个列表中的对象是nil,可能会发生意外的截断
id firstObject = @"SomeString";
id secondObject = nil;
id thirdObject = @"anotherString";
NSArray *someArray = [NSArray arrayWithObjects:firstObject, secondObject, thirdObject, nil];

使用字面常量
NSArray *someArray = @[firstObject, secondObject, thirdObject];

// 列表里不能有nil,nil是一个非法数值,会导致运行时异常
id firstObject = @"someString";
id secondObject = nil;
NSArray *someArray = @[firstObject, secondObject];
// exception: "attempt to insert nil object"
如果你需要在容器中使用nil,你应该使用NSNull单件。

查询Array
NSUInteger numberOfItems = [someArray count];
if([someArray containsObject:someString]){
  
//,,,
}
///// -------------
if([someArray count] > 0){ // 访问无效index将导致运行时异常
    NSLog(@"First item is: %@", [someArray objectAtIndex:0]);
}
//// ------ 可以使用下标语法
if([someArray count] > 0){
    NSLog(@"First item is: %@", someArray[0]);
}

Array排序
因为NSArray是不可变的,像排序这样的方法会产生一个新的array
NSArray *unsortedStrings = @[@"gammaString"@"alphaString"@"betaString"];
NSArray *sortedStrings = [unsortedStrings sortedArrayUsingSelector:@Selector(compare:)];

可变版本
NSMutableArray *mutableArray = [NSMutableArray array];
[mutableArray addObject:@"gamma"];
[mutableArray addObject:@"alpha"];
[mutableArray addObject:@"beta"];

[mutableArray replaceObjectAtIndex:0 withObject:@"epsilon"];

[mutableArray sortUsingSelector:@selector(caseInseneitiveCompare:)];

NSSet是一个无序的容器,同样是不可变的,也有可变版本。初始化同样是nil结尾。Set只为一个对象存储一个引用,哪怕你多次加入一个对象
NSNumber *number = @42;
NSSet *numberSet = [NSSet setWithObjects:number, number, number, nil];
// numberSet里仅仅有一个对象

字典是一个key-value容器,注意需要一个对象作为key,这个key对象需要依从NSCopying协议

创建字典,
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:
          someObject, @"anObject",
    
@"Hello, World1"@"helloString",
                 @42@"magicNumber",
           someValue, @"aValue",
                     nil];

使用字面常量
// 注意和上面是反的
NSDictionary 
*dictionary = @{
          @"anObject", someObject,
       @"helloString", @"Hello, World1",
       @"magicNumber", @42,
            @"aValue", someValue,,
                     }; // 没有nil

查询字典
NSNumber *storedNumber = [dictionary objectForKey:@"magicNumber"];
// or
NSNumber *storedNumber = dictionary[@"magicNumber"];

用NSNull代替nil,NSNull是一个单件,可以用等号来判断
NSArray *array = @[@"string", @42, [NSNull null] ];

for(id object in array){
    
if(object == [NSNull null]){
        NSLog(@"Found a null object");
   }
}

使用容器保存你的对象。NSArray和NSdictionary可以很容易把内容写入磁盘。如果它包含的内容是一个property list对象(NSArray,NSDictionary, NSString,NSData,NSDate和NSNumber ), 则可以从磁盘中重新创建。
NSURL *fileURL = //,,,
NSArray *array = @[@"first"@"second"@"third"];

BOOL success = [array writeToURL:fileURL atomically:YES];
if(!success){
    
// an error occured ,,,
}

//,,,,,,,,,,,,,,
NSURL *fileURL = //,,,
NSArray *array = [NSArray arrayWithContentsOfURL:fileURL];
if(!array){
    
// an error occured ,,,
}
如果是其它对象,你需要一个归档对象,诸如NSKeyedArchiver,去创建一个容器的归档。创建归档仅仅需要每一个对象实现NSCoding协议,这意味着每一个对象能够知道如何在一个归档文件里编码自己(通过实现encodeWithCoder方法)以及如何解码(实现initWithCoder方法)。

NSArray, NSSet, and NSDictionary 以及它们的可变版本都支持NSCoding,这意味着你可以归档一个复杂的对象关系。Interface Builder就是这么做的。

快速枚举,包括NSArray,NSSet,NSDictionary这样支持NSFastEnumeration协议的容器都支持OBJC语言级别的快速枚举
for(id eachObject in array){
  NSLog(@"Object: %@", eachObject);
}

for(NSString *eachKey in dictionary){
  id object = dictionary[eachKey];
  NSLog(@"Object: %@ for key: %@"object, eachKey);
}

对于有序容器,你需要自己保存索引。不能在快速枚举里改变容器,即使容器是可变的,否则将得到一个运行时异常。
int index = 0;
for(id eachObject in array){
  NSLog(@"Object at index %i is: %@", index, eachObject);
  index++;
}

枚举对象,使用NSEnumerator对象
for(id eachObject in [array reverseObjectEnumerator]){ // 反序枚举
 
//,,,
}

id eachObject;
while( (eachObject = [enumerator nextObject]) ) { // 中止时,nextObject返回nil
    NSLog(@"Current object is: %@", eachObject);
}
// 在条件语句里使用=号,会产生一个编译时警告,因此使用了双括号来消除这个警告











posted on 2013-11-21 17:34 cuigang 阅读(327) 评论(0)  编辑 收藏 引用 所属分类: OBJC


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理