上一章Objective-C开发教程请查看:Objective-C复合对象解析
从之前的章节我们已经学完所有的Objective-C语言基础了,后面开始进入高级开发的内容,包括运行时、内存管理等。
这一章主要讨论Foundation框架,说到Foundation框架,又不得不说一下Cocoa和Cocoa Touch。首先这两个都是工具集,前者用于macOS开发,后者用于iOS开发,这两个工具集有一些相同的框架,Foundation框架就是其中之一,另外Core Data也是。
另外,macOS的UI开发使用的框架是AppKit,而iOS开发使用的UI框架是UIKit。
Foundation框架是OC编程的基本框架,除了提供OOP的基本特性之外,主要还提供了:
- 一些列基本工具类,以及一些常用的数据结构。
- 支持Unicode字符串、对象持久化和对象分发。
- 日期和时间处理。
- 异常和错误处理。
- 文件处理。
- URL加载系统。
当然还有其它功能,其它的后面还是详细讨论。顺便说下,Foundation框架提供的数据结构太少了,起码再提供个堆(heap)也好。
下面我们详细介绍以上提供的功能,其中一般来说,使用指定的类,只需要导入指定的头文件即可,例如使用NSString,那么就导入Foundation/NSString.h头文件,但是为了避免导入太多的类,直接导入Foundation/Foundation.h头文件即可。
数据结构
Foundation框架中提供的数据结构也就是两种:数组和散列表,数组又包括NSArray和NSMutableArray,散列表包括NSDictionary和NSMutableDictionary,以及NSSet和NSMutableSet。
使用的时候要注意其时间复杂度,否则有可能影响APP运行效率,关于数据结构和算法更多内容,可以在srcmini中搜索获取完整的教程。
NSArray和NSMutableArray
NSArray和它的子类NSMutableArray都是有序数组,前者是静态数组,元素不可变,后者是动态数组,元素可变。因而一般来说,NSArray是直接初始化,然后使用,除非有特殊的更改元素的需求(有提供方法),否则数组都是静态不变的。而NSMutableArray在之后的使用中可能会频繁更改元素,建议使用的时候考虑元素可变和不可变的因素。
初始化NSArray可以使用initWithObjects这样的静态方法,但是更简单的方式是使用数组字面量,如下:
NSArray *array = @[someObject, @"Hello, World!", @42];
@操作符将后面的东西转为对象,这也是常见的一种用法。
方法数组元素可以使用objectAtIndex:,更简单的方式是使用下标访问法:
id value = array[3];
下面是NSArray主要提供的功能说明:
- 创建一个数组:使用静态方法,如array,arrayWtihArray,arrayWithObject等。
- 初始化数组:init,initWithObjects等。
- 数组查询:containsObject,objectAtIndex,ObjectAtIndexes等。
- 查找元素索引:indexOfObject,indexOfObject:inRange等。
- 给元素发送消息(每个元素执行指定操作):makeObjectsPerformSelector等。
- 比较数组:isEqualToArray等。
- 派生新的数组:如arrayByAddingObject。
- 数组排序:如sortedArrayUsingFunction:context。
NSMutableArray是NSArray的子类,所以以上对NSMutableArray也适用。NSMutableArray额外提供对元素操作的功能:
- removeAllObjects ——清空数组。
- addObject——在数组的末尾插入一个给定的对象。
- removeObjectAtIndex—用于删除特定索引中的对象
- exchangeObjectAtIndex:withObjectAtIndex – 交换数组中的对象。
- replaceObjectAtIndex:withObject – 用对象替换索引处的对象。
下面是一个使用示例:
#import <Foundation/Foundation.h>
int main() {
NSArray *array = [[NSArray alloc]
initWithObjects:@"string1", @"string2",@"string3",nil];
NSString *string1 = [array objectAtIndex:0];
NSLog(@"数组中下标0处的对象为 %@",string1);
NSMutableArray *mutableArray = [[NSMutableArray alloc]init];
[mutableArray addObject: @"string"];
string1 = [mutableArray objectAtIndex:0];
NSLog(@"mutableArray中下标0处的对象为 %@",string1);
return 0;
}
另外最新OC提供了泛型编程,可以在数组后面添加<Type>指定集合中的元素类型,类似于Java中的泛型。
遍历数组建议使用for-in循环,比block效率好。
NSDictionary和NSMutableDictionary
类似于上面的数组,字典也分可变和不可变两种,字典的元素的无序的,但是所有操作的时间效率都是最好的,当面向的数据不需要顺序的时候,优先使用字典。
字典中的每个元素为key-value键值对,使用方法初始化字典有点麻烦,如dictionaryWithObjects:forKeys:count,类似数组字面量使用@[],字典字面量使用@{},如:
NSDictionary *dictionary = @{
@"anObject" : someObject,
@"helloString" : @"Hello, World!",
@"magicNumber" : @42,
@"aValue" : someValue
};
要注意,字典中的key关键字也是一个对象,通常使用的是NSString对象。
在数组中访问一个元素可以使用下标,如array[1]。在字典中访问元素可以使用objectForKey方法,同样也可以使用简单的方式:
id value = dictionary[@"helloString"];
字典遍历同样建议使用for-in循环,其中每个元素为key。
NSDictionary的重要方法如下:
- alloc/initWithObjectsAndKeys——使用从指定的值和键集构造的条目初始化新分配的字典。
- valueForKey——返回与给定键关联的值。
- count——返回字典中的条目数。
NSMutableDictionary的重要方法如下:
- removeAllObjects——清空其词条的字典。
- removeObjectForKey——从字典中删除给定的键及其关联值。
- setValue:forKey——将给定的键值对添加到字典中。
下面是字典的一个简单例子:
#import <Foundation/Foundation.h>
int main() {
NSDictionary *dictionary = [[NSDictionary alloc] initWithObjectsAndKeys:
@"string1",@"key1", @"string2",@"key2",@"string3",@"key3",nil];
NSString *string1 = [dictionary objectForKey:@"key1"];
NSLog(@"key的对象,字典中的key1是 %@",string1);
NSMutableDictionary *mutableDictionary = [[NSMutableDictionary alloc]init];
[mutableDictionary setValue:@"string" forKey:@"key1"];
string1 = [mutableDictionary objectForKey:@"key1"];
NSLog(@"key的对象,mutableDictionary 中的key1是 %@",string1);
[pool drain];
return 0;
}
NSSet和NSMutableSet
集合和字典是类似的,同样是基于散列,也是无序的,只不过不需要额外提供键值,并且集合中的元素唯一。
NSSet的重要方法如下:
- alloc/initWithObjects——用指定对象列表中的成员初始化一个新分配的集合。
- allObjects——返回一个包含集合成员的数组,如果集合没有成员,则返回一个空数组。
- count——返回集合中成员的数目。
NSMutableSet继承自NSSet,因此NSSet的所有实例方法在NSMutableSet中都是可用的。
NSMutableSet的重要方法如下:
- removeAllObjects——清空其所有成员的集合。
- addObject – 如果该对象还不是集合的一个成员,则添加到集合。
- removeObject——从集合中移除给定的对象。
下面是集合的一个简单例子:
#import <Foundation/Foundation.h>
int main() {
NSSet *set = [[NSSet alloc]
initWithObjects:@"string1", @"string2",@"string3",nil];
NSArray *setArray = [set allObjects];
NSLog(@"集合对象 %@",setArray);
NSMutableSet *mutableSet = [[NSMutableSet alloc]init];
[mutableSet addObject:@"string1"];
setArray = [mutableSet allObjects];
NSLog(@"mutableSet的对象 %@",setArray);
return 0;
}
文本和字符串
Foundation支持创建和处理Unicode字符字符串,使用正则表达式查找模式,并执行文本的自然语言分析。
在这一部分,Foundation提供的功能主要是以字符为基本单位进行相关的操作,提供的主要类如下:
字符串
- NSString:一个静态的纯文本Unicode字符串对象。
- NSMutableString:一个动态的纯文本Unicode字符串对象。
字符串和元数据
- NSAttributedString:具有与其文本部分相关属性(如视觉样式、超链接或可访问性数据)的字符串。
- NSMutableAttributedString:一个可变的字符串对象,它还包含与其文本内容的各个部分相关联的属性(如可视样式、超链接或可访问性数据)。
字符
- NSCharacterSet:表示用于搜索操作的一组固定的Unicode字符值的对象。
- NSMutableCharacterSet:表示用于搜索操作的一组可变Unicode字符值的对象。
- unichar:类型为UTF-16代码单元。
自然语言处理
- NSLinguisticTagger:分析自然语言文本,标记部分语音和词汇类,识别名称,进行词化,确定语言和脚本。
模式匹配
- NSScanner:一种字符串解析器,用于扫描字符集中的子字符串或字符,以及十进制、十六进制和浮点表示法中的数值。
- NSRegularExpression:应用于Unicode字符串的已编译正则表达式的不可变表示。
本地化
- NSLocale:有关用于格式化数据以供表示的语言、文化和技术约定的信息。
- NSLocalizedStringFromTable:返回指定表中字符串的本地化版本。
时间和日期
NSDate和NSDateFormatter类提供了日期和时间的特性。
NSDateFormatter是一个帮助类,它支持将NSDate轻松地转换为NSString,反之亦然。
下面是一个简单的示例,演示如何将NSDate转换为NSString并返回到NSDate。
#import <Foundation/Foundation.h>
int main() {
NSDate *date= [NSDate date];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
[dateFormatter setDateFormat:@"yyyy-MM-dd"];
NSString *dateString = [dateFormatter stringFromDate:date];
NSLog(@"Current date is %@",dateString);
NSDate *newDate = [dateFormatter dateFromString:dateString];
NSLog(@"NewDate: %@",newDate);
return 0;
}
正如我们在上面的程序中看到的,我们在NSDate的帮助下得到了当前的时间。
NSDateFormatter是负责转换格式的类。
可以根据可用的数据更改日期格式。例如,当我们想要在上面的例子中添加时间时,日期格式可以更改为@“yyyy-MM-dd:hh:mm:ss”
异常处理
异常处理在Objective-C中是可用的,带有基础类NSException。
异常处理通过以下块实现:
- @try — 这个块尝试执行一组语句。
- @catch — 这个块试图在try块中捕获异常。
- @finally — 这个块包含一组总是执行的语句。
#import <Foundation/Foundation.h>
int main() {
NSMutableArray *array = [[NSMutableArray alloc]init];
@try {
NSString *string = [array objectAtIndex:10];
} @catch (NSException *exception) {
NSLog(@"%@ ",exception.name);
NSLog(@"Reason: %@ ",exception.reason);
}
@finally {
NSLog(@"@@finaly Always Executes");
}
return 0;
}
文件处理
文件处理在NSFileManager类的帮助下可用。这些例子不适用于在线编译器。
用于文件处理的方法
用于访问和操作文件的方法列表如下所示。在这里,我们必须将FilePath1、FilePath2和FilePath字符串替换为所需的完整文件路径,以获得所需的操作。
// 1、检查某个路径上是否存在文件
NSFileManager *fileManager = [NSFileManager defaultManager];
// 获取文件目录
NSArray *directoryPaths = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectoryPath = [directoryPaths objectAtIndex:0];
if ([fileManager fileExistsAtPath:@""] == YES) {
NSLog(@"File exists");
}
// 2、比较两个文件内容
if ([fileManager contentsEqualAtPath:@"FilePath1" andPath:@" FilePath2"]) {
NSLog(@"Same content");
}
// 3、检查是否可写、可读和可执行
if ([fileManager isWritableFileAtPath:@"FilePath"]) {
NSLog(@"isWritable");
}
if ([fileManager isReadableFileAtPath:@"FilePath"]) {
NSLog(@"isReadable");
}
if ( [fileManager isExecutableFileAtPath:@"FilePath"]) {
NSLog(@"is Executable");
}
// 4、移动文件
if([fileManager moveItemAtPath:@"FilePath1"
toPath:@"FilePath2" error:NULL]) {
NSLog(@"Moved successfully");
}
// 5、复制文件
if ([fileManager copyItemAtPath:@"FilePath1"
toPath:@"FilePath2" error:NULL]) {
NSLog(@"Copied successfully");
}
// 6、删除文件
if ([fileManager removeItemAtPath:@"FilePath" error:NULL]) {
NSLog(@"Removed successfully");
}
// 7、读取文件
NSData *data = [fileManager contentsAtPath:@"Path"];
// 8、写入文件
[fileManager createFileAtPath:@"" contents:data attributes:nil];
URL加载系统
在访问URL时,URL加载是很有用的,从互联网上获得的信息。它在下列各类的帮助下得到:
- NSMutableURLRequest
- NSURLConnection
- NSURLCache
- NSURLAuthenticationChallenge
- NSURLCredential
- NSURLProtectionSpace
- NSURLResponse
- NSURLDownload
- NSURLSession
下面是一个简单的url加载示例,这不能在命令行上运行,我们需要创建Cocoa应用程序。
这可以通过在XCode中选择New,然后在出现的窗口的OS X应用程序部分中Project和select Cocoa Application来实现。
通过单击next完成步骤的顺序,你将被要求提供一个项目名称,你可以给它一个名称。
h头文件如下所示:
#import <Cocoa/Cocoa.h>
@interface AppDelegate : NSObject <NSApplicationDelegate>
@property (assign) IBOutlet NSWindow *window;
@end
AppDelegate.m更新文件如下:
#import "AppDelegate.h"
@interface SampleClass:NSObject<NSURLConnectionDelegate> {
NSMutableData *_responseData;
}
- (void)initiateURLConnection;
@end
@implementation SampleClass
- (void)initiateURLConnection {
// 创建请求.
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://date.jsontest.com"]];
// 创建url连接和fire请求
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[conn start];
}
#pragma mark NSURLConnection Delegate Methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
// 已收到响应,这是我们初始化你创建的实例变量的地方
// 我们可以在didReceiveData方法中向它添加数据
// 而且,每次重定向时都要调用此方法,以便重新初始化它
// 也可以用来清理
_responseData = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// 将新数据附加到已声明的实例变量
[_responseData appendData:data];
}
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
willCacheResponse:(NSCachedURLResponse*)cachedResponse {
// 返回nil,表示不需要为此连接存储缓存的响应
return nil;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// 请求已经完成,数据已经收到
// 现在可以解析实例变量中的内容了
NSLog(@"%@",[[NSString alloc]initWithData:_responseData encoding:NSUTF8StringEncoding]);
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
// 由于某种原因,请求失败了!
// 检查error
}
@end
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
SampleClass *sampleClass = [[SampleClass alloc]init];
[sampleClass initiateURLConnection];
// 在这里插入代码来初始化你的应用程序
}
@end
在上面的程序中,我们创建了一个简单的URL连接,它是JSON格式的时间,并显示时间。
评论前必须登录!
注册