1.稳固的Foundation
- Foundation,顾名思义,就是两类UI框架的基础,因为它不包含UI对象,所以它的对象可以在iOS或OS X应用程序中兼容
- Foundation框架里面有很多有用的,面向数据的简单类和数据类型
2.使用项目样本代码
#import
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
NSLog(@"Hello, World!");
}
return 0;
}
默认的样本代码,之后会详细介绍
与@autoreleasepool相关的内容先暂时忽略,不使用这个关键字倒不至于引发问题,只不过在程序运行时会冒出一些奇怪的信息
3.一些有用的数据类型
3.1.范围
//创建
typedef struct _NSRange{
unsigned int location;
unsigned int length;
} NSRange;
//赋值1-直接字段赋值
NSRange range;
range.length = 17;
range.length = 4;
//赋值2-C语言的聚合结构赋值机制
NSRange range = {17,4};
//赋值3-Cocoa提供的一个快捷函数NSMakeRange()
NSRange range = NSMakeRange(17, 4);
使用NSMakeRange的好处是你可以在任何能够使用函数的地方使用它
3.2几何数据类型
- 处理图形的数据类型,它们的名称都带有CG前缀,如CGPoint,CGSize,CGRect
- 这些类型是由Core Graphics框架提供的,用来进行2D渲染
CGPoint
表示的笛卡尔平面的一个坐标(x,y)
struct CGPoint
{
float x;
float y;
};
CGSize
用来存储长度和宽度
struct CGSize
{
float width;
float height;
};
CGRect
Cocoa提供了一个矩形数据类型:它由坐标和大小复合而成
struct CGRect
{
CGFloat origin;
CGSize size;
};
- Cocoa也为我们提供了创建这些数据类型的快捷函数:CGPointMake(),CGSizeMake(),CGRectMake()
- 为什么这些数据类型是C的结构体而不是对象呢?原因就在于提高性能
4.字符串
4.1创建字符串
NSString的stringWithFormat:方法通过格式化字符串和参数来创建NSString'的
+ (id) stringWithFormat:(NSString *)format,...;
你可以通过以下方式创建一个新的字符串:
NSString *height;
height = [NSString stringWithFormat:@"Your height is %d feet, %d inches",5,11];
4.2类方法
''+ (id) stringWithFormat:(NSString *)format,...;"该方法有两个值得注意的地方
- 第一处:定义最后的省略号,它告诉我们和编译器这个方法可以接受多个以逗号隔开的其他参数
- 第二处:+号,类方法符号,这个方法属于类对象,通常用于创建新的实例,又称工厂方法(-号开头的都是对象方法)
4.3关于大小
NSString中有一个好用的方法,用来返回字符串中的字符个数
- (NSUInteger)length;
可以这样使用它:
NsUInteger length = [height length];
也可以在表达式中这样使用它:
if([height length] > 35)
{
NSLog("wow,you're really tall!");
}
4.4字符串比较
- isEqualToString:可以用来比较接收方和作为参数传递过来的字符串,并且会返回一个BOOL值来表示这两个字符串是否相同
//声明
- (BOOL) isEqualToString:(NSString *) aString;
//使用方法
NSString *thing1 = @"hello 5";
NSString *thing2 =[NSString stringWithFormat:@"hello %d",5];
if ([thing1 isEqualToString:thing2]) {
NSLog(@"They are the same");
}
- compare:方法,将接受对象和传递过来的字符串逐个比较,并返回一个NSComparisonResult(枚举值)
//声明
- (NSComparisonResult) compare : (NSString *) aString;
//NSComparisonResult(枚举值)
enum
{
NSOrderedAscending = -1;//左侧的数值小于右侧的数值,也就是说比较的目标在字母表中的排序位置比传递进来的字符串更靠前
NSOrderedSame,//相等
NSOrderedDescending//右侧数值小于左侧的数值
};
typedef NSInteger NSComparisonResult;
- 运算符==:检查两个字符串是否为同一事物,比较的指针数值而不是对象
- isEqualToString:检查两个字符串是否内容相等
4.5不区分大小写的比较
compare:options:方法
- (NSComparisonResult) compare: (NSString *) aString
options:(NSStringCompareOptions) mask;
options是一个掩位码,可以使用(|)来添加选项标记
//常用的选项
NSCaseInsensitiveSearch:不区分大小写
NSLiteralSearch:进行完全的比较,区分大小写
NSNumericSearch:比较字符串的字符个数
//例子
if([thing1 compare : thing2
options:NSCaseInsensitiveSearch | NSNumericSearch] = NSOrderedSame )
4.6字符串内是否还包含别的字符串
- 判断字符串是否以另一个字符串开头:
- (BOOL) hasPrefix: (NSString *) aString;
- 判断字符串是否以另一个字符串结尾:
- (BOOL) hasPSuffix: (NSString *) aString;
- 判断字符串是否包含其他字符串:
//返回一个NSRange结构体,告诉你与这个字符串相匹配的部分在哪里以及能够匹配上的字符个数
- (NSRange) rangeOfString: (NSString *) aString;
例子:
#import
int main(int argc, const char * argv[]) {
NSString *fileName = @"draft-chapter.pages";
if ([fileName hasPrefix:@"draft"])
{
NSLog(@"YES");
}
if ([fileName hasSuffix:@".pages"]) {
NSLog(@"YES");
}
NSRange range = [fileName rangeOfString:@"chapter"];
NSLog(@"位置:%lu,长度:%lu",range.location,range.length);
return 0;
}
//运算结果
2018-10-09 09:43:34.253294-0700 a[620:27675] YES
2018-10-09 09:43:34.253461-0700 a[620:27675] YES
2018-10-09 09:43:34.253504-0700 a[620:27675] 位置:6,长度:7
Program ended with exit code: 0
4.7可变性
NSString是不可变的,这并不是说你不能操作它,而是一旦被创建,便不能改变,但是你可以用它生成新的字符串,查找字符串或者将它与其它字符串进行比较
NSString的子类:NSMutableString
1.类方法stringWithCapacity:来创建一个新的NSMutableString,这个容量只是一个最优值,字符串的大小并不局限于所提供的容量
+ (id) stringWithCapacity:(NSUInteger) capacity;
2.一旦有了一个可变字符串,就可以对它执行各种操作
//附加新的字符串
- (void) appendString:(NSString *) aString;
- (void) appendFormat:(NSString *) format,...;
//删除字符串的中的字符
- (void) deleteCharactersInRange:(NSRange) aRange;
示例:
#import
int main(int argc, const char * argv[]) {
//创建
NSMutableString *friend = [NSMutableString stringWithCapacity:50];
//添加
[friend appendString:@"jack unlikes jam"];
//找范围
NSRange unrange = [friend rangeOfString:@"un"];
//删除
[friend deleteCharactersInRange:unrange];
//输出
NSLog(@"%@",friend);
return 0;
}
//运算结果
2018-10-09 10:17:54.657861-0700 a[682:35185] jack likes jam
Program ended with exit code: 0
3.注意:
- 任何使用NSString的地方,都可以使用NSMutableString
- 由于继承,NSString中非常方便的stringWithFormat:也可以用来创建新的NSMutableString对象
NSMutableString *string = [NSMutableString stringWithFormat:@"jo%ddy",2];
5.集合大家族
NSArray和NSDictionary,他们的实例就是为了存储其他对象而存在的
5.1.NSArray
1.NSArray是一个Cocoa类,用来存储同一种类型对象的有序列表
2.可以将数组当做参数传递给方法或者函数,获取数组中所村对象的个数,提取某个索引值所对应的对象,查找数组中的对象,遍历数组
3.NSArray类有两个限制:首先,它只能存储OC对象,不能存储原始的C语言基础数据类型,同时你也不能存储nil(对象的零值或NULL),有很多方法可以避开限制
4.NSArray
- 类方法arrayWithObject:创建一个新的NSArray
//发送一个以对象分隔的对象列表,在结尾添加nil代表列表结束(这就是不能存储nil的原因)
NSArray *array = [NSArray arrayWithObjects:@"one", @"two",@"three",nil];
//数组字面量格式
NSArray *array1 = @[@"one", @"two",@"three"];
- 获取数组包含的对象
- (NSUInteger)count;
- 获取特定索引处的对象
- (id)objectAtIndex:(NSUInteger)index;
- 示例:
#import
int main(int argc, const char * argv[]) {
//结合技术和取值功能输出数组中的内容
NSArray *array = [NSArray arrayWithObjects:@"one", @"two",@"three",nil];
for(NSInteger i = 0; i < [array count]; i++){
NSLog(@"index %ld has %@.",i,[array objectAtIndex:i]);
}
//使用数组字面量语法输出数组中的内容
for(NSInteger i = 0; i < [array count]; i++){
NSLog(@"index %ld has %@.",i,array[i]);
}
return 0;
}
//输出结果
2018-10-10 09:39:55.232395-0700 a[564:14489] index 0 has one.
2018-10-10 09:39:55.232593-0700 a[564:14489] index 1 has two.
2018-10-10 09:39:55.232603-0700 a[564:14489] index 2 has three.
2018-10-10 09:39:55.232635-0700 a[564:14489] index 0 has one.
2018-10-10 09:39:55.232658-0700 a[564:14489] index 1 has two.
2018-10-10 09:39:55.232683-0700 a[564:14489] index 2 has three.
Program ended with exit code: 0
可变数组
1.与可变数组一样,NSArray创建的是一个不可变数组,一旦你创建了一个包含特定数量的对象的数组,他就固定下来,可以改变它所包含对象,但是你不能添加任何元素也不能删除任何元素
2.NSMutableArray
- 类方法arrayWithCapacity:创建
//数组容量只是数组最终大小的一个参考
//他之所以存在,是为了Cocoa能够对代码进行优化
//Cocoa是不会用容量来限制数组的大小的
+ (id) arrayWithCapacity: (NSUInteger) numItems;
- 数组末尾添加对象
- (void) addObject: (id) anyObject;
- 删除特定索引处的对象
- (void) removeObjectAtIndex: (NSUInteger) index;
- 特定所索引处插入对象,替换对象,为数组排序,以及从NSSArray继承的功能
- 示例:
#import
//Tire类
@interface Tire : NSObject
@end
@implementation Tire
@end
int main(int argc, const char * argv[]) {
NSMutableArray *array = [NSMutableArray arrayWithCapacity:17];
//[NSArray arrayWithObjects:@"one", @"two",@"three",nil];
for (NSUInteger i = 0; i < 4; i++) {
Tire *tire = [Tire new];
[array addObject:tire];
}
[array removeObjectAtIndex:1];
return 0;
}
5.2.NSDictionary
- 字典是关键字及其定义的集合,它能在给定的关键字(通常是一个NSString字符串)下存储一个数值(可以是任意类型的OC对象),然后你就可以用这个关键字来查找相应的数据
1.NSDictionary
- 创建
类方法 dictionaryWithObjectsAndKeys:
//dictionaryWithObjectsAndKeys:后面的参数先是要存储的对象,然后才是关键字,以nil作为终止符号(NSDictionary不能存储nil值)
+ (id) dictionaryWithObjectsAndKeys: (id) firstObject,...;
字面量语法
//关键字在前,数值在后,关键字与数值之间用冒号隔开,每对键值之间则用逗号区分开
@{key:value,...};
- 访问
//类方法 objectForKey:
- (id)objectForKey:(id)aKey;
//字面量
类 [key];
- 示例:
#import
//Tire类
@interface Tire : NSObject
@end
@implementation Tire
@end
//主函数
int main(int argc, const char * argv[]) {
Tire *t1 = [Tire new];
Tire *t2 = [Tire new];
Tire *t3 = [Tire new];
Tire *t4 = [Tire new];
NSDictionary *tires1 = [NSDictionary dictionaryWithObjectsAndKeys:t1,@"front- left",t2,@"front- right", t3,@"back- left",t4,@"back- right",nil];
NSDictionary *tires2 = @{@"front- left":t1,@"front- right":t2,@"back- left":t3,@"back- right":t4};
Tire *tire1 = [tires1 objectForKey:@"black-right"];
Tire *tire2 = tires2 [@"black-right"];
//如果对应键值无对象,返回nil
NSLog(@"%@ ,%@",tire1,tire2);
return 0;
}
//运行结果
2018-10-11 16:42:05.330267-0700 a[682:29345] (null) ,(null)
Program ended with exit code: 0
2.NSMutableDictionary
NSMutableDictionary允许你添加和删除字典元素,与NSArray一样,没有适用于NSMutableDictionary的字面量初始化方法
创建:
类方法dictionaryWithCapacity:
//同样的,这里的容量仅仅只是一个建议
+ (id) dictionaryWithCapacity:(NSUInteger) numItems;
对象方法setObject:forKey:
NSMutableDictionary *tires = [NSMutableDictionary dictionary];
[tires setObject:t1 forKey:@"front- left"];
[tires setObject:t2 forKey:@"front- right"];
[tires setObject:t3 forKey:@"back- left"];
[tires setObject:t4 forKey:@"back- right"];
- 替换添加:
setObject:forKey:可以添加元素,也可以用新的值替换原有的数值
- (void)setObject: (id) anObject forKey:(id) aKey;
- 删除添加:
- (void) removeObjectForKey: (id) aKey;
5.3.枚举
- NSArray经常要对数组中的每个元素都执行同一个操作。你可以编写一个从0到[array count]的循环来读取每个索引处的对象,也可以使用NSEnumerator,Cocoa可以用它来表示集合中迭代处的对象。
//要想使用NSEnumerator,需要通过ObjectiveEnumerator向数组请求枚举器
- (NSEnumerator *) objectiveEnumerator;
//你可以使用这个方法:
NSEnumerator *enumerator = [array objectEnumerator];
- 如果你想要从后面浏览某个集合,还有一个reverseObjectiveEnumerator方法可以使用。
- 在获得枚举器后,便可以开始一个while循环,每次循环都向这个枚举器请求它的nextObject(下一个对象):
-(id)nextObjective;
- nextObjective返回nil值时,循环结束。这也是不能在数组中存储nil值得另一个原因:我们没有方法判断nil是存储在数组中的数值还是代表循环结束的标志。
NSEnumerator *enumerator = [array objectEnumerator];
while (id thingie = [enumerator nextObject])
{
NSLog(@"I found %@",thingie);
}
- 对可变数组进行枚举操作时,有一点需要注意:你不能通过添加或者删除对象这类方式来改变数组的容量。如果这么做了,枚举器就会出现混乱,你也会获得未定义结果。“未定义结果可以代表任何意思。”
5.4.快速枚举
- 我们要介绍的第一个改进叫做快速枚举,它的语法与脚本语言类似,如下面的代码所示。
for (NSString *string in array)
{
NSLog(@"I found %@",string);
}
- 这个循环体将会遍历数组中大的每一个元素,并且用变量string来存储每个数组值,它比枚举器语法更简洁快速。
- 新版本的苹果编译器为纯c语言添加了一个叫做代码块的特性。为了支持代码块功能,苹果公司添加了一个能在NSArray中通过代码块枚举对象的方法。
- (void)enumerateObjectsUsingBlock:(void (^)(id obj,NSUInteger idx,BOOL *stop))block
//我们用之前的那个数组来重写这个枚举方式。
[array enumerateObjectsUsingBlock:^(NSString *string,NSUInteger index,BOOL *stop){
NSLog(@"I found %@",string);
}];
“我们为什么要用它来代替快速枚举呢?”因为通过代码块可以让循环操作并发执行,而通过快速枚举,执行操作要一项一项地线性完成。
好了,我们现在有四种方法遍历数组了:通过索引、使用NSEnumerator、使用快速枚举和最新的代码块方法。
6.其他数值
- NSArray和NSDictionary只能存储对象,不能直接存储任何基本类型的数据,如int,float和struct等,不过你可以使用对象来封装基本数值.
- 如果你想要使用对象来处理基本类型,就可以使用NSInteger和NSUInteger
int、 NSInteger、 NSUInteger、NSNumber之间的区别和联系
int : 当使用int类型定义变量的时候,可以像写C程序一样,用int也可以用NSInteger,推荐使用NSInteger ,因为这样就不用考虑设备是32位还是64位了。
NSUInteger是无符号的,即没有负数,NSInteger是有符号的。
NSInteger是基础类型,NSNumber是一个类,如果需要存储一个数值,直接使用NSInteger是不行的
比如在一个数组里使用下面的语句就会报错:
NSArray *array = [NSArray alloc] init];
[array addObject:3];
因为array里应该是一个类,但‘3’不是,所以需要用NSNumber:
NSArray *array = [NSArray alloc] init];[array addObject:[NSNumber numberWithInt:3]];
6.1.NSNumber
- Cocoa提供了NSNumber类来封装基本数据类型
//类方法创建
+ (NSNumber *) numberWithChar:(char)value;
+ (NSNumber *) numberWithInt:(int)value;
+ (NSNumber *) numberWithFloat:(float)value;
+ (NSNumber *) numberWithBOOL:(BOOL)value;
//格式:
NSNumber 数字对象 = [NSNumber numberWith数字类型:数值];
//字面量语法
NSNumber *number;
number = @'x';//字符型
number = @12345;//整型
number = @12345ul;//无符号长整数
number = @12345ll//long long
number = @123.45f;//浮点型
number = @123.45;//双浮点型
number = @YES;//布尔值
- 获取:
在将一个基本数据类型封装到NSNumber中后,可以通过实例方法重新获得它
- (char) charValue;
- (int) intValue;
- (float) floatValue;
- (BOOL) boolValue;
- 说明:
通常将一个基本类型的数据封装成对象的过程被称为装箱
从对象中提取基本类型的数据叫做开箱
6.2.NSValue
- NSNumber实际上是NSValue的子类,它可以封装任何值
//创建NSValue对象
+ (NSValue *) valueWithBytes: (const void *) value objCType: (const char *) type;
//第一个参数传递的是封装的数值的地址
//第一个参数传递的是封装的数值的类型
- 示例:
//创建NSValue,将结构体放入其中
NSRect rect = NSMakeRect (1,2,30,40);
NSValue *value = [NSValue valueWithBytes:&rect objCType:@encode(NSRect)];
[array addObject:value];
//使用getValue:来提取数值
- (void) getValue:(void *) buffer;
//调用getValue:时,需要传递存储这个数值的变量地址
value = [array objectAtIndex:0];
[value getValue:&rect];
- Cocoa提供了常用的结构体转换成NSValue的便捷方法:
+ (NSValue *) valueWithPoint:(NSPoint)apoint;
+ (NSValue *) valueWithSize:(NSSize)size;
+ (NSValue *) valueWithRect:(NSRect)rect;
- (NSPoint)pointValue;
- (NSSize)sizeValue;
- (NSRect)rectValue;
//可以按照下列方法在NSArray中存储和提取NSRect的值
value = [NSValue valueWithRect:rect];
[array addObject:value];
...
NSRect anotherRect = [value rectValue];
6.3.NSNull
- 我们说过nil不能放入NSArray和NSDictionary中,因为nil在其中有特殊含义。NSNull就是设置什么都没有的
+ (NSNull *) null;
- 示例:
//添加
[contact setObject:[NSNull null] forKey:@"home fax machine"];
//访问
id homefax = [contact objectForKey:@"home fax machine"];
if (homefax == [NSNull null])
{
//......确定没有传真机后的行为
}
7.示例:查找文件
- 下面是一个实用的程序,它是用本章中介绍的类组成的,FileWalker程序
- 可以查找你在Mac电脑上的主目录以及查找.jpg文件并打印到列表中
- FileWalker程序用到了NSString,NSArray,NSEnumerator和其他两个用来与文件系统交互的Foundation类
- 用到了NSFileManager,它允许你对文件系统进行操作,例如创建目录,删除文件,移动文件,或者获取文件信息
#import
int main(int argc, const char * argv[]) {
//自动释放池
@autoreleasepool {
//创建NSFileManager对象
NSFileManager *manger;
manger = [NSFileManager defaultManager];
//代表主目录的速记符号“~”代表/Users/用户名/
//NSString中有一个方法可以接受~字符并将其展开成主目录路径
NSString *home;
home = [@"~" stringByExpandingTildeInPath];
//将路径字符串传递给文件管理器
//enumeratorAtPath:返回一个NSDirectoryEnumerator对象,他是NSEnumerator的子类
//每次枚举器调用nextObject方法时,都会返回目录中下一个文件的路径
NSDirectoryEnumerator *direum;
direum = [manger enumeratorAtPath:home];
//初始化数组
NSMutableArray *files;
files = [NSMutableArray arrayWithCapacity:42];
//目录枚举器会返回一个代表文件路径的NSString字符串
//当枚举器结束时它会返回nil值,于是循环终止
NSString *filename;
while (filename = [direum nextObject]) {
//嵌套的方法来获取路径扩展名并将获得的字符串传给isEqualToString:方法
//如果调用结果为YES,则该文件将会被添加到文件数组中
if ([[filename pathExtension] isEqualToString:@".png"] ) {
[files addObject:filename];
}
}
//目录循环结束后,遍历文件数组,用NSLog()函数将数组内容输出
NSEnumerator *fileenum;
fileenum = [files objectEnumerator];
while (filename = [fileenum nextObject]) {
NSLog(@"filename");
}
}
return 0;
}