AppDelegate.h
#import <Cocoa/Cocoa.h>
#import "MyProtocol.h"
@interface AppDelegate : NSObject <NSApplicationDelegate,NSTableViewDataSource,NSTabViewDelegate,MyProtocol>
{
IBOutlet NSTableView *tableView;
NSArray *classes;
}
@end
AppDelegate.m
#import "AppDelegate.h"
#import "ScheduleFetcher.h"
#import "ScheduledClass.h"
@interface AppDelegate ()
@property (weak) IBOutlet NSWindow *window;
@end
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
[tableView setTarget:self];
[tableView setDoubleAction:@selector(openClass:)];
ScheduleFetcher *fetcher = [[ScheduleFetcher alloc]init];
NSError *error = nil;
classes = [fetcher fetchClassesWithError:&error];
[tableView reloadData];
// NSLog(@"*****************************%@", [NSThread currentThread]);
//
// [fetcher fetchClassesWithBlock:^(NSArray *theClasses, NSError *error) {
// if (theClasses) {
// classes = theClasses;
// [tableView reloadData];
// }else{
// NSAlert *alert = [[NSAlert alloc]init];
// [alert setAlertStyle:NSAlertStyleCritical];
// [alert setMessageText:@"Error locading schedule."];
// [alert setInformativeText:[error localizedDescription]];
// [alert addButtonWithTitle:@"OK"];
// [alert beginSheetModalForWindow:self.window modalDelegate:nil didEndSelector:nil contextInfo:nil];
// }
// NSLog(@"qqqqqqqqqqqqqqqqqqqqqqqq%@", [NSThread currentThread]);
// }];
// NSLog(@"*****************************%@", [NSThread currentThread]);
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
// Insert code here to tear down your application
}
#pragma mark 委托
//在tabViewItem被选中之前调用
- (BOOL)tabView:(NSTabView *)tabView shouldSelectTabViewItem:(nullable NSTabViewItem *)tabViewItem{
return YES;
}
//通知委托,tabView将会选择tabViewItem
- (void)tabView:(NSTabView *)tabView willSelectTabViewItem:(nullable NSTabViewItem *)tabViewItem{
}
//通知委托,tabView已经选择了tabViewItem。
- (void)tabView:(NSTabView *)tabView didSelectTabViewItem:(nullable NSTabViewItem *)tabViewItem{
}
//通知委托,tabView中的选项卡视图条目的数量已经改变。
- (void)tabViewDidChangeNumberOfTabViewItems:(NSTabView *)tabView{
}
#pragma mark 数据源协议
//行数
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView{
return [classes count];
}
//绑定值
- (nullable id)tableView:(NSTableView *)tableView objectValueForTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row{
ScheduledClass *c= [classes objectAtIndex:row];
return [c valueForKey:[tableColumn identifier]];
}
-(void)openClass:(id)sender{
ScheduledClass *c = [classes objectAtIndex:[tableView clickedRow]];
NSURL * baseUrl = [NSURL URLWithString:@"http://www.baidu.com/"];
NSURL * url = [NSURL URLWithString:[c href] relativeToURL:baseUrl];
[[NSWorkspace sharedWorkspace]openURL:url];//打开浏览器
}
- (void)content:(NSArray *)myClasses forError:(NSError *)error {
if (myClasses) {
classes = myClasses;
[tableView reloadData];
}else{
NSAlert *alert = [[NSAlert alloc]init];
[alert setAlertStyle:NSAlertStyleCritical];
[alert setMessageText:@"Error locading schedule."];
[alert setInformativeText:[error localizedDescription]];
[alert addButtonWithTitle:@"OK"];
[alert beginSheetModalForWindow:self.window modalDelegate:nil didEndSelector:nil contextInfo:nil];
}
}
@end
ScheduledClass.h
#import <Foundation/Foundation.h>
@interface ScheduledClass : NSObject
{
NSString *name;//名称
NSString *location;//地点
NSString *href;//链接
NSDate *begin;//开始时间
}
@property (nonatomic,copy) NSString *name;
@property (nonatomic,copy) NSString *location;
@property (nonatomic,copy) NSString *href;
@property (nonatomic,copy) NSDate *begin;
@end
ScheduledClass.m
#import "ScheduledClass.h"
@implementation ScheduledClass
@synthesize name,location,href,begin;
@end
ScheduledFetcher.h
#import <Foundation/Foundation.h>
#import "MyProtocol.h"
//创建一个块
typedef void (^ScheduleFetcherResultBlock)(NSArray*classes,NSError*error);
//实现NSURLConnectionDataDelegate协议
@interface ScheduleFetcher : NSObject<NSXMLParserDelegate,NSURLConnectionDataDelegate>
{
NSMutableArray *classes;//类别
NSMutableString *currentString;//当前字符
NSMutableDictionary *currentFields;//当前字段
NSDateFormatter * dateFormatter;//日期格式
ScheduleFetcherResultBlock resultBlock;//创建块对象
NSMutableData *responseData;//返回数据
NSURLConnection *connection;//连接请求
id<MyProtocol> myDelegate;
}
@property (strong) id<MyProtocol> myDelegate;
-(void)fetchClassesWithBlock:(ScheduleFetcherResultBlock)theBlock;
//如果成功则返回一个NSArray,失败则返回nil
-(NSArray*)fetchClassesWithError:(NSError**) outError;
@end
ScheduledFetcher.m
#import "ScheduleFetcher.h"
#import "ScheduledClass.h"
#import "AppDelegate.h"
@implementation ScheduleFetcher
@synthesize myDelegate;
- (instancetype)init
{
self = [super init];
if (self) {
myDelegate = [[AppDelegate alloc]init];
classes = [[NSMutableArray alloc]init];
dateFormatter = [[NSDateFormatter alloc]init];
//设置日期格式
[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss zzzz"];
}
return self;
}
-(void)fetchClassesWithBlock:(ScheduleFetcherResultBlock)theBlock{
//复制块,保证其并不知存在栈中
resultBlock = [theBlock copy];
NSURL *xmlURL= [NSURL URLWithString:@"http://www.baidu.com/"];
NSURLRequest *req = [NSURLRequest requestWithURL:xmlURL cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:30];
connection = [[NSURLConnection alloc]initWithRequest:req delegate:self];
if (connection) {
responseData = [[NSMutableData alloc]init];
}
}
-(void)cleanup{
responseData = nil;
connection = nil;
resultBlock = nil;
}
#pragma mark-
#pragma mark NSURLConnection Delegate
//添加数据
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
[responseData appendData:data];
}
//解析数据
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
[classes removeAllObjects];
NSXMLParser *parser = [[NSXMLParser alloc]initWithData:responseData];
[parser setDelegate:self];
BOOL success =[parser parse];
if (!success) {
resultBlock(nil,[parser parserError]);
}else{
NSArray*output = [classes copy];
resultBlock(output,nil);
}
[self cleanup];
}
//连接失败
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
resultBlock(nil,error);
[self cleanup];
}
//如果成功则返回一个NSArray,失败则返回nil
-(NSArray*)fetchClassesWithError:(NSError**) outError{
BOOL success;
//@"http://bignerdranch.com/xml/schedule"
//1 NURL 设置访问地址
NSURL *xmlURL= [NSURL URLWithString:@"http://www.baidu.com/"];
//2 NSURLRequest 请求,缓存策略,超时
NSURLRequest *request = [NSURLRequest requestWithURL:xmlURL cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:30];
NSURLResponse *resp = nil;
//3 NSURLConnection执行连接
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&resp error:outError];
if (!data) {
return nil;
[myDelegate content:nil forError:*outError];
}
[classes removeAllObjects];
//开始解析
NSXMLParser *parser;
parser = [[NSXMLParser alloc]initWithData:data];
[parser setDelegate:self];//设置委托
success = [parser parse];//解析是否成功
if (!success) {
*outError = [parser parserError];
[myDelegate content:nil forError:*outError];
return nil;
}
NSArray *output = [classes copy];
[myDelegate content:output forError:nil];
return output;
// NSLog(@"Received %ld bytes",[data length]);
// return nil;
}
#pragma mark-
#pragma mark NSXMLParserDelegate Methods
//元素的标记开始
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary<NSString *,NSString *> *)attributeDict{
if ([elementName isEqual:@"class"]) {
currentFields =[[NSMutableDictionary alloc]init];
}else if([elementName isEqual:@"offering"]){
[currentFields setObject:[attributeDict objectForKey:@"href"] forKey:@"href"];
}
}
//元素的标记结束
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if([elementName isEqual:@"class"]){
ScheduledClass *currentClass = [[ScheduledClass alloc]init];
[currentClass setName:[currentFields objectForKey:@"offering"]];
[currentClass setLocation:[currentFields objectForKey:@"location"]];
[currentClass setHref:[currentFields objectForKey:@"href"]];
NSString *beginString = [currentFields objectForKey:@"begin"];
NSDate *beginDate = [dateFormatter dateFromString:beginString];
[currentClass setBegin:beginDate];
currentClass = nil;
currentFields = nil;
}else if(currentFields&¤tString){
NSString *trimmed;
trimmed = [currentString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
[currentFields setObject:trimmed forKey:elementName];
}
currentString = nil;
}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if (!currentString) {
currentString = [[NSMutableString alloc]init];
}
[currentString appendString:string];
}
@end
MyProtocol.h
#import <Foundation/Foundation.h>
@protocol MyProtocol <NSObject>
-(void)content:(NSArray*)myClasses forError:(NSError*)error;
@end