⑩--Foundation框架基础

来源:互联网 发布:天猫淘宝棉拖鞋 编辑:程序博客网 时间:2024/05/01 00:09

OC的基本语法告一段落了,今天开始学习Foundation框架。

1.Foundation框架介绍

之前已经介绍了什么是框架以及如何使用一个框架。Foundation框架是其他所有iios框架的基础

Foundation框架包含了很多开发中常用的数据类型:

√结构体

√枚举

√类

要想使用Foundation框架中的数据类型,包含它的主头文件即可

#import <Foundation/Foundation.h>

下面介绍Foundation框架中的一些常见的基本用法。

2.常用结构体--NSRange、NSPoint/CGPoint、NSSize/CGSize、NSRect\CGRect

①NSRange是表示范围的结构体,它在Foundation中的定义如下:

typedef struct _NSRange {    NSUInteger location;    NSUInteger length;} NSRange;

可以看出NSRange有两个变量组成:

一个是代表位置的location;

一个是代表长度的length。

这两个变量的类型都是NSUInteger类型,对于NSUInteger其实就是无符号的长整型:

#if __LP64__ || (TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE) || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64typedef long NSInteger;typedef unsigned long NSUInteger;#elsetypedef int NSInteger;typedef unsigned int NSUInteger;#endif

NSRange有如下的用途:

例如@"i love oc"这个字符串中,有个子串@"love",他在@"i love oc"中的范围用NSRange表示就是:location为2,length为4.

如何声明并初始化一个NSRange:

按照C语言中对结构体初始化的方法:

NSRange r1 = {2, 4}; // 不用NSRange r2= {.location = 2, .length = 4}; // 不用
上面的两种初始化方法在官方是不推荐的,它推荐使用下面的方式进行初始化:

NSRange r3 = NSMakeRange(2, 4); // 掌握


NSRange常见的一个用法

查找某个字符串在str中的范围

NSString *str = @"i love oc";// 查找某个字符串在str中的范围NSRange range1 = [str rangeOfString:@"love"];NSLog(@"loc = %ld, length = %ld", range1.location, range1.length); // ->loc = 2, length = 4

如果找不到,length = 0location=NSNotFound==-1%d

NSString *str = @"i love oc";// 查找某个字符串在str中的范围// 如果找不到,length = 0,location=NSNotFound==-1%dNSRange range2 = [str rangeOfString:@"java"];NSLog(@"loc = %ld, length = %ld", range2.location, range2.length); // ->loc = NSNotFound ,length = 0

(注:实际上上面loc的值是9223372036854775807 它其实表示的是长整型数值的-1)

②NSPoint\CGPoint、NSSize/CGSize、NSRect\CGRect

顾名思义,我们可以猜测NSPoint表示的是点,实际上NSPoint的定义为:

typedef CGPoint NSPoint;

而CGPoint的定义为:

struct CGPoint {  CGFloat x;  CGFloat y;};typedef struct CGPoint CGPoint;
显然CGPoint里面定义了表示点的两个坐标值:x和y。它们都是CGFloat类型的数据:

# define CGFLOAT_TYPE doubletypedef CGFLOAT_TYPE CGFloat;

可见CGFloat其实就是double类型。

按照刚才初始化一个NSRange类型的数据的方式初始化一个NSPoint:

CGPoint p1 = NSMakePoint(10, 10);

但实际上最常用的是另一种方法:

NSPoint p2 = CGPointMake(10, 10); // 最常用

再看NSSize/CGSize,它们在Foundation中的定义是这样的:

typedef CGSize NSSize;

struct CGSize {  CGFloat width;  CGFloat height;};typedef struct CGSize CGSize;

同样地,也有初始化它们的类似方法:

NSSize s1 = NSMakeSize(100, 50);NSSize s2 = CGSizeMake(100, 50);

再看NSRect\CGRect,它们的定义如下:
typedef CGRect NSRect;struct CGRect {  CGPoint origin;  CGSize size;};typedef struct CGRect CGRect;

NSRect\CGRect常用来表示UI元素在屏幕中的区域,包括CGPoint类型的原点origin,和CGSize类型的size。

初始化它们有如下方法:

NSRect r1 =  CGRectMake(0, 0, 100, 50); //方式1CGRect r2 = {{0, 0}, {100, 90}}; // 方式2CGPoint p1 = NSMakePoint(10, 10);NSSize s1 = NSMakeSize(100, 50);CGRect r3 = {p1, s1}; // 方式3
也可以这样初始化:

CGRect r4 = {CGPointZero, CGSizeMake(100, 90)};

其中CGPointZero == CGPoint(0, 0);表示(0, 0)点。

在Foundation中拥有将结构体直接转为字符串的全局方法:

NSRect r1 =  CGRectMake(0, 0, 100, 50);NSString *str = NSStringFromRect(r1); // 将结构体转为字符串打印NSLog(@"%@", str);
输出的结果为:

2014-12-28 10:52:24.514 01-结构体[615:303] {{0, 0}, {100, 50}}
NSPoint\CGPoint、NSSize/CGSize、NSRect\CGRect有就几个在开发中常用的函数:

// 使用这些函数的前提是添加CoreGraphic框架// 比较两个点是否相同(x, y)BOOL b = CGPointEqualToPoint(CGPointMake(10, 10), CGPointMake(10, 10));BOOL b1 = CGRectContainsPoint(CGRectMake(0, 0, 100, 50), CGPointMake(2, 3));NSLog(@"%d", b1);

输出结果为:

2014-12-28 10:55:06.695 01-结构体[626:303] 1

3.NSString类和NSMutableString类

①NSString类

NSString类也就是OC中的字符串类,很多用法已经不陌生了。

创建一个NSString对象的方法:

NSString *s1 = @"12212";//NSString *s2 = [[NSString alloc] initWithString:@"df"]; // 太繁琐// 3.创建格式化的字符串NSString *s3 = [[NSString alloc] initWithFormat:@"age is %d", 10];    // 4.C语言字符串----> OC字符串NSString *s4 = [[NSString alloc] initWithUTF8String:"C语言字符串"];

上面可以看到一中C语言字符串转为OC字符串的方法,OC字符串也可以转为C语言字符串:

// OC字符串------->c语言字符串const char *cs = [s4 UTF8String];

还有更强大的用法,从一个文件中获取字符串:

// NSUTF8StringEncoding 用到中文就可以用这种编码NSString *s5 = [[NSString alloc] initWithContentsOfFile:@"/Users/Mike/Desktop/note/目标.txt" encoding:NSUTF8StringEncoding error:nil];

还可以从一个URL中获取字符串:

为此我们先定义一个URL:

NSURL *url = [[NSURL alloc] initWithString:@"file:///Users/Mike/Desktop/note/目标.txt"]; // 创建失败

但实际上,像上面这样带中文的URL是不会创建成功的,解决的方案有三种:

方案一:如果是文件,使用URL类的fileURLWithPath函数:

NSURL *url = [NSURL fileURLWithPath:@"/Users/Mike/Desktop/note/目标.txt"];// 可以*******

方案二:将路径中的中文改为这个中文的Unicode编码:

NSURL *url = [[NSURL alloc] initWithString:@"http://mike.qiniudn.com/%E8%AF%AD%E8%A8%80%E5%AD%A6%E4%B9%A0%E6%A0%91%E5%BD%A2%E5%9B%BE2.html"]; ///可以****

方案三:使用NSString的函数将中文转为Unicode编码再操作:
NSString *sUrl = [@"file:///Users/Mike/Desktop/note/目标.txt" stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];NSURL *url = [[NSURL alloc] initWithString:sUrl];
要注意URL路径的格式规则:

协议头://路径

"file:///Users/Mike/Desktop/note/目标.txt"
"http://www.baidu.com/index.php"


注意****************

以上方法可以直接使用类方法 不用每次都alloc

一般都会有个类方法跟对象方法配对

****************

例如:

[[NSString alloc] initWithFormat:@"age is %d", 10];

可以直接写成:

[NSString stringWithFormat:@"age is %d", 10];


而对于

[[NSURL alloc] initWithString:sUrl];

直接写成:

[NSURL URLWithString:sUrl];

也就是将“ alloc+initWith”改成“类With”。这是通用的做法。

字符串还有一些写入方法,如将字符串写到文件中:

[@"jack" writeToFile:@"file:///Users/Mike/Desktop/note/a.txt" atomically:YES encoding:NSUTF8StringEncoding error:nil];
当然还有writeToURL等方法。
②NSMutableString

NSMutableString是可变的字符串,它继承自NSString.但是又针对"可变"扩展了很多方法。


NSMutableString常用的方法有,拼接字符串到当前字符串后面:

NSMutableString *s1 = [NSMutableString stringWithFormat:@"age is 10"];    [s1 appendFormat:@" 11 12"]; // 尾部添加NSLog(@"s1 = %@", s1); // s1 = age is 10 11 12

删除字符串中的字符:

</pre></p><p><span style="font-size:14px;"></span><pre name="code" class="objc">NSMutableString *s1 = [NSMutableString stringWithFormat:@"age is 10"];[s1 deleteCharactersInRange:NSMakeRange(4, 2)]; //删除isNSLog(@"s1 = %@", s1); // s1 = age  10

上面的操作的需要传入字符的范围,比较麻烦,可以使用如下方法简化:

NSMutableString *s1 = [NSMutableString stringWithFormat:@"age is 10"];[s1 deleteCharactersInRange:[s1 rangeOfString:@"is"]]; //删除isNSLog(@"s1 = %@", s1); // s1 = age  10

对于NSString也可以实现上面的字符串拼接功能,但是NSString不可变,必须要用新的值就接受拼接后的字符串:

NSString *s2 = [NSString stringWithFormat:@"age is 10"];    NSString *s3 = [s2 stringByAppendingString:@" 11 12"]; // s2不变 新的字符串用s3接收NSLog(@"s2 = %@, s3 = %@", s2, s3); // s2 = age is 10, s3 = age is 10 11 12

这就体现出了NSString和NSMutableString的区别:不可变和可变

4.NSArray和NSMutableArray

类似于Java的集合类,OC中有NSArray、NSSet、NSDictionary.

①NSArray是数组类可以存放一些数据,类型是可以不同的,但是存放在NSArray中是有序的

为什么要引入NSArray数组类,先看C语言中数组的局限性:

√C语言的数组不够灵活,只能存放一种数据类型;

√C语言的数组面向过程,几乎没有什么可以操作数组的方法,且操作起来非常困难。

而NSArray解决了上面的问题,但也有一定的要求:

√OC数组只能存放oc对象不能存放非OC对象,如int、struct、enum等等;

√OC数组不能存放空值(数组以nil为结束)。

创建一个数组:

NSArray *array = [NSArray array]; // 
但是这个数组永远是空数组,因为NSArray不可变,创建时没有指定元素,所以长度为0但是又不能添加元素。

应当这样创建:

NSArray *array2 = [NSArray arrayWithObjects:@"jack", nil];
并且以nil作为结束。

数组类的常用操作:获取数组元素的个数:

NSLog(@"%ld", array3.count);

访问数组的元素(按索引):

NSLog(@"%@", [array3 objectAtIndex:1]);

这种写法有种简化:

NSLog(@"%@", array3[0]); // 编译器特性 
这是种编译器特性,实际上会讲array3[0]转换为 [array3objectAtIndex:0];

还有一种针对NSArray的编译器特性,用于快速创建数组:

NSArray *array4 = @[@"jack", @"rose"];// 编译器特性 实际使用了arrayWithObjects
这时候不能再加上结束标识nil,否则报错。
若想对数组进行遍历操作:可用的方法有很多种:

方法一:

NSArray *array = @[p, @"rose", @"jack"];// 方法1for (int i = 0; i < array.count; i++){    NSLog(@"%@", array[i]);}


方法二:(for each)

// 方法2    for (id obj in array) // 快速遍历数组元素{    NSUInteger i = [array indexOfObject:obj]; // 找出obj元素在数组中的位置    NSLog(@"%ld----%@", i, obj);}


方法三:使用遍历方法enumerate并用block做参数
// 方法3// 没遍历到一个元素,就会调用一次block// 并且当前元素和索引位置当做参数传给block[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {    NSLog(@"%ld---%@", idx, obj);}];

其内部相当于执行了下面的代码:

void ^(myblock)(id, NSUInteger, BOOL *) = ^(id obj, NSUInteger idx, BOOL *stop){    NSLog(@"%ld - %@", idx, obj);};for (int i = 0; i<array.count; i++){    // 用来标记是否需要停止遍历    BOOL isStop = NO;    // 取出元素    id obj = array[i];           myblock(obj, i, &isStop);                    if (isStop)    {        break;    }}

②NSMutableArray

NSMutableArray是可变的数组,它继承自NSArray。

NSMutableArray常用的操作有:

创建一个可变数组:要以nil结束

NSMutableArray *array = [NSMutableArray arrayWithObjects:@"rose", @"jim", nil];

向数组中添加元素:

NSMutableArray *array = [NSMutableArray array];// 添加元素[array addObject:[[Person alloc] init]];    [array addObject:@"jack"];
注意不能添加nil值的元素,因为nil是数组结束的标识。

[array addObject:nil]; // 错误写法


删除指定的元素:

// 删除指定的对象[array removeObject:@"jack"];

按照索引删除元素:

[array removeObjectAtIndex:0];


删除所有的元素:
// 删除所有的元素[array removeAllObjects];

注意:@[]只创建不可变数组 ,例如:

NSMutableArray *array = @[@"jack", @"rose"];
当这一句执行时编译器值发生了警告:因为根据编译器特性@[@"jack",@"rose"];会转换成代码

[NSArrayarrayWithObjects:@"jack",@"rose",nil]; 这样赋值=的右边产生了一个NSArray对象,因此会产生类型不匹配的警告:

Incompatible pointer types initializing 'NSMutableArray *' with an expression of type 'NSArray *'

若要继续添加下面这句:

[array addObject:@"jim"];
就会引发错误:

[__NSArrayI addObject:]: unrecognized selector sent to instance

因为array本质上是一个NSArray而不是NSMutableArray,他不存在addObject方法。

5.NSSet和NSMutableSet
①NSSet

NSSet也是一种集合类,它与NSArray最大的区别就是:

NSArray中的元素是有顺序的,因此NSArray中有索引的概念

NSSet中的元素是没有顺序的,就像数学中的集合Set具有无序性。

创建一个NSSet:

NSSet *s = [NSSet set]; // 永远为空的NSSet    NSSet *s2 = [NSSet setWithObjects:@"jack",@"rose", @"jack2",@"jack3",nil];

取出一个元素:

// 随机拿出一个元素NSString *str =  [s2 anyObject];    NSLog(@"%@", str);

②NSMutableSet

可变的Set,常用操作:

添加元素:

// 添加元素[s addObject:@"hack"];

删除元素

// 删除元素[s removeObject:(id)];

6.NSDictionary和NSMutableDictionary

①NSDictionary常被成为字典,相当于Java中HashMap,以键值对的形式存放数据,在开发中有非常对的使用。

创建一个NSDictionary对象

方式一:

添加一个键值对key:@"name",value:@"jack"

// 创建方式1NSDictionary *dict = [NSDictionary dictionaryWithObject:@"jack" forKey:@"name"];
方式二:

有多个键值对时,可以用两个数组分别存放keys和values,利用方法

dictionaryWithObjects:  forKeys:

// 创建方式2NSArray *keys = @[@"name", @"address"];NSArray *objs = @[@"jack", @"北京"];NSDictionary *dict = [NSDictionary dictionaryWithObjects:objs forKeys:keys];

方式三:

采用一个值value一个键key的方式赋值

// 创建方式3NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:@"jack", @"name", @"北京", @"address", @"123456", @"QQ", nil]; // 注意添加结束标识nil


利用Xcode编译器特性,快速创建

// 编译器特性*************NSDictionary *dict = @{@"name":@"jack", @"address":@"北京"};

取出一个元素:

id obj = [dict objectForKey:@"name"];    NSLog(@"%@", obj); // jack

利用编译器特性,取出元素:

// 编译器特性**************obj = dict[@"address"];    NSLog(@"%@", obj); // 北京

②NSMutableDictionary

创建一个NSMutableDictionary:

NSMutableDictionary *dict = [NSMutableDictionary dictionary];

添加键值对:setObject方法

// 添加键值对[dict setObject:@"jack" forKey:@"name"];[dict setObject:@"北京" forKey:@"address"];

注意:给存在的key赋值,旧值被覆盖

// 给相同的key赋值时 旧值会覆盖[dict setObject:@"rose" forKey:@"name"];
此时的name为rose;

移除键值对:根据key来移除

[dict removeObjectsForKeys:@"name"];

数组和字典的打印:

NSLog(@"%@", @[@"jack",@"rose"]);  // 数组NSLog(@"%@",@{@"name":@"jack", @"address":@"北京"}); //字典

输出的结果是:

(    jack,    rose){    address = "\U5317\U4eac";    name = jack;}


与NSArray类似下面的,写法也是错误的:

NSMutableDictionary *dict = @{@"name":@"jack"};    [dict setObject:@"rose" forKey:@"name"];

NSDictionary 遍历

方法一:比较繁琐,依次取出key和value

NSDictionary *dict = @{@"name":@"jack",                       @"address":@"北京",                       @"qq":@"123456"};    // 方法1NSArray *keys = [dict allKeys];for (int i = 0; i <  dict.count; i++){    id key = keys[i];    id obj = dict[key];        NSLog(@"%@ = %@", key, obj);}

方法二:利用block

// 方法2 用block非常方便[dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {    NSLog(@"%@ = %@", key, obj);}];

对集合的总结:

集合:

1.NSArray\NSMutableArray

*有序

*快速创建(不可变)@[obj1, obj2, obj3];

*快速访问元素:数组名[i]


2.NSSet\NSMutableSet

*无序

*无快速创建的方法


3.NSDictionary\NSMutableDictionary

*无序

*快速创建(不可变)@{key1value1, key2:value2};

*快速访问元素:字典名[key];


7.NSNumber和NSValue

在前面的集合操作中,我们可以看到NSArray、NSSet和NSDictionary都只能存放OC的对象数据,然而对于基本数据类型char、int、float、double、enum和结构体struct都无法存放。NSNumber和NSValue就是用来解决这一问题的,使用NSNumber和NSValue来包装这些类型,可以让它们转换为对象类型的数据。

①NSNumber

将BOOL、char、int、float、double、NSInteger类型的数据包装成NSNumber类型的对象

NSNumber *b = [NSNumber numberWithBool:YES];NSNumber *c = [NSNumber numberWithChar:'A'];NSNumber *i = [NSNumber numberWithInt:10];NSNumber *f = [NSNumber numberWithFloat:0.1f];NSNumber *d = [NSNumber numberWithDouble:6.345];NSNumber *integer = [NSNumber numberWithInteger:1056];
***********************************************注意

NSInteger不是对象类型,不要看到NS开头就以为是对象类型,他可能是结构体、枚举、常量等,NSInteger的定义如下:

#if __LP64__ || (TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE) || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64typedef long NSInteger;typedef unsigned long NSUInteger;#elsetypedef int NSInteger;typedef unsigned int NSUInteger;#endif
可以看到在64位的编译器中NSInteger就是long,在32位的编译器中就是int

************************************************

不过每次都使用numberWith方法未免过于繁琐:利用编译器特性像下面这样包装即可:

NSNumber *b = @YES; // BOOL类型NSNumber *c = @'A'; // char类型 注意和字符串的区别NSNumber *i = @10; // int类型NSNumber *f = @0.1f; // float类型NSNumber *d = @6.345; // double类型NSNumber *integer = @1056; // NSInteger类型
不仅仅如此,还可以这样包装数据

int a = 10;NSNumber *na = @(a);
这样的话,用了这么多天的NSLog();函数中的%d,%f什么的格式符都可以换成%@了(窃喜~~),多么强大的编译器特性。
可以用包装好的数据测试一下了:
NSNumber *num = [NSNumber numberWithInt:10]; // 或者使用NSNumber *num = @10;NSDictionary *dict = @{                           @"name" : @"jack",                           @"age" : num                           };
上面的代码现在一点错误也没有了,但是此时若用dict[@"age"];取出的是NSNumber类型,如何将它再转为基本数据类型呢?

方法是这样的:

NSNumber *num2 = dict[@"age"];int age = [num2 intValue];    NSLog(@"age = %d", age); // age = 10
类似的,对于其他类型也可以采用相应的方法:类型Value。


需要注意的是NSString类型也有类似的方法:

[@"10" intValue]; // 10
NSNumber不仅返回基本数据类型,还可以返回NSString类型的数据:

NSNumber *num2 = dict[@"age"];NSString *age = [num2 stringValue];    NSLog(@"age = %@", age); // age = 10

对NSNumber类型的分析:

NSNumber之所以能包装数据,是因为继承了NSValue ,

NSNumber只能包装数字类型,若要包装结构体就得使用NSValue。

使用NSValue将结构体包装成NSValue类型的OC对象:

// 将结构体包装成OC对象CGPoint p = CGPointMake(10, 10);// 将结构体转为NSValueNSValue *value = [NSValue valueWithPoint:p];


注意此时绝对不能这样写:

NSValue *value = @(p);
这种写法只适用于NSNumber包装的类型。


如何将NSValue类型对象转为对应的结构体:

// 将value转为对应的结构体CGPoint p2 =  [value pointValue];


8.NSDate类

NSDate是日期时间类,一个NSDate对象不仅包含了年月日信息,还有时间等信息,同时还有许多操作日期和时间的方法。

创建一个时间对象:当前时间

NSDate *date = [NSDate date]; // 默认依据当前时间
打印时间:
NSLog(@"%@", date); // 2014-12-28 08:06:36 +0000
创建一个时间对象:比date晚5秒钟

NSDate *date2 = [NSDate dateWithTimeInterval:5 sinceDate:date];

获取从1970年1月1日凌晨走过的秒数:

// 从1970开始走过的秒数NSTimeInterval seconds = [date2 timeIntervalSince1970];
这里的NSTimeInterval实际是double类型:

typedef double NSTimeInterval;

获取date与当前时间的间隔:单位:妙

[date2 timeIntervalSinceNow];// Returns the interval between the receiver and the current date and time

日期格式化类的使用:

使用一:将date对象转为字符串:

void dateToString(){    NSDate *date = [NSDate date];        // 日期格式化类    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];    // H(24小时制) h(12小时制)    formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss";    NSString *strDate = [formatter stringFromDate:date];    NSLog(@"%@", strDate);}

使用二:将字符串转为日期:

void strToDate(){    NSString *time = @"2011/09/10 18:56";        NSDateFormatter *formatter = [[NSDateFormatter alloc] init];    formatter.dateFormat = @"yyyy/MM/dd HH:mm";        NSDate *date = [formatter dateFromString:time];        NSLog(@"%@", date);}



0 0
原创粉丝点击