这篇文章是"ios局域网联机——苹果官方源码之WiTap剖析"系列的第4部分,它和第3部分紧紧相连,因此阅读此文章的前提是你已经阅读了这个系列的第3部分。
直捣黄龙
在上一篇文章中我们提到要想理解AppController类的presentPicker方法必须先了解BrowserViewController类,并且上一篇文章中我们已经对这个BrowserViewController类进行了全面的了解,现在是时候回过头来看这个presentPicker方法了。
打开AppController文件,我们来看这个方法的实现:
1 - (void) presentPicker:(NSString *)name { 2 if (!_picker) { 3 _picker = [[Picker alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame] type:[TCPServer bonjourTypeFromIdentifier:kGameIdentifier]]; 4 _picker.delegate = self; 5 } 6 7 _picker.gameName = name; 8 9 if (!_picker.superview) {10 [_window addSubview:_picker];11 }12 }
首先我们看到这个方法是有一个参数name的,它的作用是传给AppController的变量_picker,让_picker设置自己的一个Label的显示内容的。
第2 行,判断这个_picker是否为空。
第3 行,如果这个_picker是空的话,初始化一个Picker类的实例,并把这个实例赋给_picker
第4行,调用Picker类的属性delegate的set方法。
第5行,调用Picker类的属性gameName的set方法。
第9-10行,如果这个_picker还没有加入到_window(我们的程序的主窗口)的话,就把它作为子视图加入到_window里。
好,我们来看看Picker类的实现,先看Picker.h文件:
1 #import <UIKit/UIKit.h> 2 #import "BrowserViewController.h" 3 4 @interface Picker : UIView { 5 6 @private 7 UILabel *_gameNameLabel; 8 BrowserViewController *_bvc; 9 }10 11 @property (nonatomic, assign) id<BrowserViewControllerDelegate> delegate;12 @property (nonatomic, copy) NSString *gameName;13 14 - (id)initWithFrame:(CGRect)frame type:(NSString *)type;15 16 @end
第1-2行,导入需要的UIKit框架和BrowserViewController的头文件。
第4 行,可以看到,这个类是继承自UIView的。
第7-8行,声明两个私有变量,一个是一个Label,用来显示游戏的名字,一个是BrowserViewController类的一个实例,用来搜索相应的服务。
第10-11行,声明两个属性,一个是一个符合BrowserViewControllerDelegate协议的委托;一个是游戏名字的字符串。
第14行,这个类的初始化方法,带有两个参数,一个是表示这个view的大小的,一个要搜索的服务的类型。
接着来看看具体的实现,打开Picker.m文件:
1 #import "Picker.h" 2 3 #define kOffset 5.0 4 5 @interface Picker () 6 @property (nonatomic, retain, readwrite) BrowserViewController *bvc; 7 @property (nonatomic, retain, readwrite) UILabel *gameNameLabel; 8 @end 9 10 @implementation Picker11 12 @synthesize bvc = _bvc;13 @synthesize gameNameLabel = _gameNameLabel;
几乎合之前所有的.m文件的实现都一样,这里是先包含.h文件,然后定义了一个宏,接着为刚才那两个私有变量添加属性,然后为这两个新添加的属性合成set和get方法。
先看这个类的清理方法:
1 - (void)dealloc {2 // Cleanup any running resolve and free memory3 [self.bvc release];4 [self.gameNameLabel release];5 6 [super dealloc];7 }
这是一些必要的清理操作,不做过多陈述。
再来看一下这里为在Picker.h文件里添加的那两个属性实现的set和get方法:
- (id<BrowserViewControllerDelegate>)delegate { return self.bvc.delegate;}- (void)setDelegate:(id<BrowserViewControllerDelegate>)delegate { [self.bvc setDelegate:delegate];}- (NSString *)gameName { return self.gameNameLabel.text;}- (void)setGameName:(NSString *)string { [self.gameNameLabel setText:string]; [self.bvc setOwnName:string];}
我们可以看到其实这些set和get方法还是有些特殊性的。
delegate的get方法返回的是这个Picker类的bvc属性的delegate,set方法也是设置的这个Picker类的bvc属性的delegate。
这个gameName的get方法是返回这个Picker类的gameLabel属性的text,set方法不光设置了Picker类的gameLabel的text,还对这个Picker类的bvc调用了ownName调用了set方法(上一篇文章已经讲过了BrowserViewController类的所有方法了)。
然后来看这个Picker类的初始化方法:
1 - (id)initWithFrame:(CGRect)frame type:(NSString*)type { 2 3 if ((self = [super initWithFrame:frame])) { 4 // add autorelease to the NSNetServiceBrowser to release the browser once the connection has been 5 // established. An active browser can cause a delay in sending data. 6 // <rdar://problem/7000938> 7 self.bvc = [[[BrowserViewController alloc] initWithTitle:nil showDisclosureIndicators:NO showCancelButton:NO]autorelease]; 8 [self.bvc searchForServicesOfType:type inDomain:@"local"]; 9 10 self.opaque = YES;11 self.backgroundColor = [UIColor blackColor];12 13 UIImageView* img = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"bg.png"]];14 [self addSubview:img];15 [img release];16 17 CGFloat runningY = kOffset;18 CGFloat width = self.bounds.size.width - 2 * kOffset;19 20 UILabel* label = [[UILabel alloc] initWithFrame:CGRectZero];21 [label setTextAlignment:UITextAlignmentCenter];22 [label setFont:[UIFont boldSystemFontOfSize:15.0]];23 [label setTextColor:[UIColor whiteColor]];24 [label setShadowColor:[UIColor colorWithWhite:0.0 alpha:0.75]];25 [label setShadowOffset:CGSizeMake(1,1)];26 [label setBackgroundColor:[UIColor clearColor]];27 label.text = @"Waiting for another player to join game:";28 label.numberOfLines = 1;29 [label sizeToFit];30 label.frame = CGRectMake(kOffset, runningY, width, label.frame.size.height);31 [self addSubview:label];32 33 runningY += label.bounds.size.height;34 [label release];35 36 self.gameNameLabel = [[UILabel alloc] initWithFrame:CGRectZero];37 [self.gameNameLabel setTextAlignment:UITextAlignmentCenter];38 [self.gameNameLabel setFont:[UIFont boldSystemFontOfSize:24.0]];39 [self.gameNameLabel setLineBreakMode:UILineBreakModeTailTruncation];40 [self.gameNameLabel setTextColor:[UIColor whiteColor]];41 [self.gameNameLabel setShadowColor:[UIColor colorWithWhite:0.0 alpha:0.75]];42 [self.gameNameLabel setShadowOffset:CGSizeMake(1,1)];43 [self.gameNameLabel setBackgroundColor:[UIColor clearColor]];44 [self.gameNameLabel setText:@"Default Name"];45 [self.gameNameLabel sizeToFit];46 [self.gameNameLabel setFrame:CGRectMake(kOffset, runningY, width, self.gameNameLabel.frame.size.height)];47 [self.gameNameLabel setText:@""];48 [self addSubview:self.gameNameLabel];49 50 runningY += self.gameNameLabel.bounds.size.height + kOffset * 2;51 52 label = [[UILabel alloc] initWithFrame:CGRectZero];53 [label setTextAlignment:UITextAlignmentCenter];54 [label setFont:[UIFont boldSystemFontOfSize:15.0]];55 [label setTextColor:[UIColor whiteColor]];56 [label setShadowColor:[UIColor colorWithWhite:0.0 alpha:0.75]];57 [label setShadowOffset:CGSizeMake(1,1)];58 [label setBackgroundColor:[UIColor clearColor]];59 label.text = @"Or, join a different game:";60 label.numberOfLines = 1;61 [label sizeToFit];62 label.frame = CGRectMake(kOffset, runningY, width, label.frame.size.height);63 [self addSubview:label];64 65 runningY += label.bounds.size.height + 2;66 67 [self.bvc.view setFrame:CGRectMake(0, runningY, self.bounds.size.width, self.bounds.size.height - runningY)];68 [self addSubview:self.bvc.view];69 70 }71 72 return self;73 }
第3行,根据参数frame的大小初始化这个picker类(它是继承自UIView的)。
第7-8行,对bvc属性(BrowserViewController类)进行初始化,并在特定域中搜索特定服务。
第10-11行,设置自己为不透明,并设置自己的背景颜色。
第13-15行,给自己加一个背景图片。
第17-63行,给自己加3个label,其中包括一个就是gameNameLabel属性,gameNameLabel属性用来显示游戏的名字(目前只是设置为@""了,但是在上一篇文章中我们已经了解了,当它搜索到自己发布的服务的时候,会把它设置自己发布的服务的名字),其它两个label是显示的一些提示性信息。
第65-68行,设置Picker类的bvc属性的view(即BrowserViewController这个tableViewController的tableView)的显示范围,并把这个bvc的view作为子视图加入到picker里。
第72行,返回自己。
现在这个AppController类的presentPicker方法是不是完全明白了?呵呵
其实到这儿为止,这个例子里所涉及到的关键操作基本上都讲到了,剩下没讲的方法的就是一些具体的操作上的东西了,我在后面会大致的讲一下它们的作用,不再逐句解释。
下面来迅速地说明一下这些剩余的方法的作用。首先是TapView.h文件:
1 #import <UIKit/UIKit.h> 2 3 @interface TapView : UIView 4 { 5 BOOL localTouch; 6 BOOL remoteTouch; 7 } 8 9 - (void) touchDown:(BOOL)remote;10 - (void) touchUp:(BOOL)remote;11 12 @end
我们看到这个TapView是继承自UIView的,它有两个布尔变量用来标识是远程的touch还是本地的touch。两个方法表示按下和抬起手指时针对的处理方法。
来看TapView.m文件:
1 - (void) touchDown:(BOOL)remote 2 { 3 // set "tap down" visual state if necessary 4 if(!localTouch && !remoteTouch) 5 self.frame=CGRectInset(self.frame, kActivationInset, kActivationInset); 6 7 if (remote) 8 remoteTouch = YES; 9 else10 localTouch = YES;11 }
这个方法是在手指按下游戏中的色块时把色块变小来表示色块被点击了,并同时设置相应的远程或本地触摸的标记为真。
1 - (void) touchUp:(BOOL)remote 2 { 3 BOOL wasDown = localTouch || remoteTouch; 4 5 if (remote) 6 remoteTouch = NO; 7 else 8 localTouch = NO; 9 10 BOOL isDown = localTouch || remoteTouch;11 12 // run "tap up" visual animation if necessary13 if(wasDown != isDown) {14 [UIView beginAnimations:nil context:NULL];15 [UIView setAnimationDuration:0.1];16 self.frame = CGRectInset(self.frame, -kActivationInset, -kActivationInset);17 [UIView commitAnimations];18 }19 }
这个方法是在手指点击游戏中的色块后手指离开屏幕时用来恢复色块大小为原始大小,并还原相应的远程或本地触摸标识为假。
1 - (void) localTouchUp2 {3 [self touchUp:NO];4 [(AppController*)[[UIApplication sharedApplication] delegate] deactivateView:self];5 }
这个方法是在当发生的是本机的触摸事件时调用的方法,它调用touchUp方法,并给这个方法的表示远程触摸的参数传入假,然后调用AppController的deactivateView方法。
然后是touch事件的3个协议方法:
1 - (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event 2 { 3 [self touchDown:NO]; 4 [(AppController*)[[UIApplication sharedApplication] delegate] activateView:self]; 5 } 6 7 - (void) touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event 8 { 9 [self localTouchUp];10 }11 12 - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event13 {14 [self localTouchUp];15 }
在began方法里是调用touchDown方法,并传入NO给touchDown方法中表示远程的参数。end方法和cancel方法都只是调用localTouchUp方法而已。
回头望月
是时候回到AppController类认真地看一下了,来看看它的头文件AppController.h吧:
#import "TapView.h"#import "BrowserViewController.h"#import "Picker.h"#import "TCPServer.h"@interface AppController : NSObject <UIApplicationDelegate, UIActionSheetDelegate, BrowserViewControllerDelegate, TCPServerDelegate, NSStreamDelegate>{ UIWindow *_window; Picker *_picker; TCPServer *_server; NSInputStream *_inStream; NSOutputStream *_outStream; BOOL _inReady; BOOL _outReady;}- (void) activateView:(TapView*)view;- (void) deactivateView:(TapView*)view;@end
在这里可以看到它包含了我们前面讲过的所有的主要的类,这一看就是要做大事的类呀呵呵。再看它声明自己遵守的协议,呵呵,有五个之多。
实例变量_window这是我们的主窗口,_picker一个Picker类的实例,用来搜索和显示发布的特定服务,_server这个TCPServer类的实例用来发布服务,_inStream和_outStream这是一对输入输出流,然后一对布尔变量_inReady和_outReady表示输入输出流的准备状态。
一对方法用来激活和去激活我们在游戏中的色块。
来看看这个AppController的具体实现,打开AppController.m文件:
1 #import "AppController.h" 2 #import "Picker.h" 3 4 #define kNumPads 3 5 #define kGameIdentifier @"witap" 6 7 8 @interface AppController () 9 - (void) setup;10 - (void) presentPicker:(NSString *)name;11 @end
没有过多要解释的东西,这里的东西该解释的前面都已经解释过了呵呵。
1 - (void) _showAlert:(NSString *)title2 {3 UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:title message:@"Check your networking configuration." delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];4 [alertView show];5 [alertView release];6 }
这个是用来显示警告信息的。
applicationDidFinishLaunching方法,dealloc方法,setup方法,presentPicker方法我们都已经讲过了,接着是destroyPicker方法:
1 - (void) destroyPicker {2 [_picker removeFromSuperview];3 [_picker release];4 _picker = nil;5 }
这个是在我们进入游戏后,销毁用来显示搜索到的服务列表的视图(即_picker)的。
1 - (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex2 {3 [self setup];4 }
这个方法是在当我们在远端设备断开连接的时候显示一个错误或警告的时候,点击了警告上的按钮的话调用的方法,这是重新调用setup方法,重新开始新的服务发布和搜索过程。
1 - (void) send:(const uint8_t)message2 {3 if (_outStream && [_outStream hasSpaceAvailable])4 if([_outStream write:(const uint8_t *)&message maxLength:sizeof(const uint8_t)] == -1)5 [self _showAlert:@"Failed sending data to peer"];6 }
这个是用来发送消息对无端设备的,其实就是向输出流写入数据。
1 - (void) activateView:(TapView *)view2 {3 [self send:[view tag] | 0x80];4 }5 6 - (void) deactivateView:(TapView *)view7 {8 [self send:[view tag] & 0x7f];9 }
游戏中色块的激活和去激活方法,它们的实现内容都是调用send方法,不同的是向send方法发送的数据不一样。
1 - (void) openStreams2 {3 _inStream.delegate = self;4 [_inStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];5 [_inStream open];6 _outStream.delegate = self;7 [_outStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];8 [_outStream open];9 }
打开输入输出流,并把它们加入到当前runLoop中,并把它们的委托设为AppController自己。
1 - (void) browserViewController:(BrowserViewController *)bvc didResolveInstance:(NSNetService *)netService 2 { 3 if (!netService) { 4 [self setup]; 5 return; 6 } 7 8 // note the following method returns _inStream and _outStream with a retain count that the caller must eventually release 9 if (![netService getInputStream:&_inStream outputStream:&_outStream]) {10 [self _showAlert:@"Failed connecting to server"];11 return;12 }14 [self openStreams];15 }
这个是在解析我们要连接的服务完成的时候,在BrowserViewController的NSNetService的协议方法里调用的。这里做的处理是,如果这个解析的服务无效,重新调用setup方法并返回。接着对这个服务调用getInputStrem:outPutStream方法来判断这个连接是否真正连接好。然后调用openStreams方法,打开输入输出流。(这个方法是在发起连接服务的设备上调用的)
1 - (void) stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode 2 { 3 4 UIAlertView *alertView; 5 switch(eventCode) { 6 case NSStreamEventOpenCompleted: 7 { 8 NSLog(@"case open completed\n"); 9 [self destroyPicker];10 11 [_server release];12 _server = nil;13 14 if (stream == _inStream)15 _inReady = YES;16 else17 _outReady = YES;18 19 if (_inReady && _outReady) {20 NSLog(@"show the message game started\n");21 alertView = [[UIAlertView alloc] initWithTitle:@"Game started!" message:nil delegate:nil cancelButtonTitle:nil otherButtonTitles:@"Continue", nil];22 [alertView show];23 [alertView release];24 }25 break;26 }27 case NSStreamEventHasBytesAvailable:28 {29 NSLog(@"case has bytes available\n");30 if (stream == _inStream) 31 {32 uint8_t b;33 int len = 0;34 len = [_inStream read:&b maxLength:sizeof(uint8_t)];35 if(len <= 0) 36 {37 if ([stream streamStatus] != NSStreamStatusAtEnd)38 [self _showAlert:@"Failed reading data from peer"];39 } 40 else 41 {42 //We received a remote tap update, forward it to the appropriate view43 if(b & 0x80)44 [(TapView *)[_window viewWithTag:b & 0x7f] touchDown:YES];45 else46 [(TapView *)[_window viewWithTag:b] touchUp:YES];47 }48 }49 break;50 }51 case NSStreamEventErrorOccurred:52 {53 NSLog(@"case error occurred\n");54 [self _showAlert:@"Error encountered on stream!"]; 55 break;56 }57 58 case NSStreamEventEndEncountered:59 {60 NSLog(@"case end encountered\n");61 NSArray *array = [_window subviews];62 TapView *view;63 UIAlertView *alertView;64 65 66 //Notify all tap views67 for(view in array)68 [view touchUp:YES];69 70 alertView = [[UIAlertView alloc] initWithTitle:@"Peer Disconnected!" message:nil delegate:self cancelButtonTitle:nil otherButtonTitles:@"Continue", nil];71 [alertView show];72 [alertView release];73 74 break;75 }76 default:77 {78 NSLog(@"case there is no corresponding case match this event\n");79 }80 }81 }
这个方法比较重要,这个是流的协议方法。根据不同的流事件做不同的处理:
当流事件是流打开完成的时候,销毁_picker,释放_service,根据触发事件的流设置对就的准备好状态为真,当输入输出两个流都准备好的时候,显示一个警告窗口告诉我们游戏开始。
当流事件是有可用数据的时候,判断这个触发事件的流是不是输入流,如果是就处理,不是就不处理。当是输入流触发事件的时候,从流中读出信息,如果读取出错的话显示一个警告,如果成功的话,根据得到的数据,相应的激活或去激活相应的色块。(具体这个地方的位运算,只要把send方法发送的数据转成2进制就明白这个地方位运算的意义了)
当流事件是出现错误的时候,显示一个警告。(前面已经说过了如果这个警告上的按钮被点击的话会调用setup方法重新开始整个过程)
当流事件是流已经结束的时候(比如远端设备连接断开的时候),把所有色块恢复原始状态,显示一个警告,说明对方断开连接。
其它事件情况下输出一条log语句,没有相应的匹配的事件。
最后是两个TCPServerDelegate协议的方法:
1 - (void) serverDidEnableBonjour:(TCPServer *)server withName:(NSString *)string2 {3 [self presentPicker:string];4 }
这个是在服务发布成功之后,让_picker显示服务的名字的。
1 - (void)didAcceptConnectionForServer:(TCPServer *)server inputStream:(NSInputStream *)istr outputStream:(NSOutputStream *)ostr 2 { 3 4 if (_inStream || _outStream || server != _server) 5 return; 6 7 [_server release]; 8 _server = nil; 9 10 _inStream = istr;11 [_inStream retain];12 _outStream = ostr;13 [_outStream retain];14 15 [self openStreams];16 }
这个是在接受了服务的连接请求之后调用的(这个方法只会在被动连接的一方设备上调用)。如果输入或输出流其中有一个有效或者这个方法中的server参数不是这个被连接的设备上的服务本身的话,直接返回。
如果不是上述情况的话,就释放并停止这个服务,把它赋为nil,把输入输出流赋值为参数istr和ostr,打开输入输出流。
重新理顺所有逻辑
到此,这个例子中所有的方法我们基本上都讲完了,现在你应该能知道这个例子中的每一个方法干了什么了,但是这个只是明白了每个方法干了什么还是不够的,目前看来我们的逻辑还是不够清晰,不够顺畅。下面我给出这个例子的执行流程(并不是所有方法都列了出来,是绝大多数都列出来了),对照着这个流程来看每个方法会很容易理清楚所有的逻辑的。
执行流程下载地址
(一)真机和模拟器一起调试,模拟器作为连接发起方时的执行过程:
下面的过程是模拟器运行后自动执行的程序流程
[AppController.m]--[applicationDidFinishLaunching:]
[AppController.m]--[setup]
[TCPServer.m]--[init]
[TCPServer.m]--[start:]
[TCPServer.m]--[bonjourTypeFromIdentifier:]
[TCPServer.m]--[enableBonjourWithDomain:applicationProtocol:name:]
[AppController.m]--[presentPicker:]
[TCPServer.m]--[bonjourTypeFromIdentifier:]
[Picker.m]--[initWithFrame:type:]
[BrowserViewController.m]--[initWithTitle:showDisclosureIndicators:showCancelButton:]
[BrowserViewController.m]--[searchForServicesOfType:inDomain:]
[BrowserViewController.m]--[stopCurrentResolve]
[BrowserViewController.m]--[setTimer:]
[BrowserViewController.m]--[numberOfSectionsInTableView:]
[BrowserViewController.m]--[tableView:numberOfRowsInSection:]
[BrowserViewController.m]--[searchingForServicesString]
[Picker.m]--[setDelegate:]
[Picker.m]--[setGameName:]
[BrowserViewController.m]--[setOwnName:]
[TCPServer.m]--[netServiceDidPublish:]
[AppController.m]--[serverDidEnableBonjour:withName:]
[AppController.m]--[presentPicker:]
[Picker.m]--[setGameName:]
[BrowserViewController.m]--[setOwnName:]
[BrowserViewController.m]--[numberOfSectionsInTableView:]
[BrowserViewController.m]--[tableView:numberOfRowsInSection:]
[BrowserViewController.m]--[searchingForServicesString]
[BrowserViewController.m]--[netServiceBrowser:didFindService:moreComing:]
the service is: <NSNetService 0x4b3fb00> local. _witap._tcp. dingwenjie
[BrowserViewController.m]--[sortAndUpdateUI]
[BrowserViewController.m]--[numberOfSectionsInTableView:]
[BrowserViewController.m]--[tableView:numberOfRowsInSection:]
[BrowserViewController.m]--[searchingForServicesString]
[BrowserViewController.m]--[initialWaitOver:]
[BrowserViewController.m]--[numberOfSectionsInTableView:]
[BrowserViewController.m]--[tableView:numberOfRowsInSection:]
[BrowserViewController.m]--[searchingForServicesString]
下面的过程是真机运行程序后,模拟器自动执行的程序流程
[BrowserViewController.m]--[netServiceBrowser:didFindService:moreComing:]
the service is: <NSNetService 0x4e1b840> local. _witap._tcp. “DWJ”的 iPad
[BrowserViewController.m]--[sortAndUpdateUI]
[BrowserViewController.m]--[numberOfSectionsInTableView:]
[BrowserViewController.m]--[tableView:numberOfRowsInSection:]
[BrowserViewController.m]--[tableView:cellForRowAtIndexPath:]
下面的过程点击了模拟器的服务列表之后,建立了联机状态
[BrowserViewController.m]--[tableView:willSelectRowAtIndexPath:]
[BrowserViewController.m]--[tableView:didSelectRowAtIndexPath:]
[BrowserViewController.m]--[setTimer:]
[BrowserViewController.m]--[netServiceDidResolveAddress:]
[BrowserViewController.m]--[stopCurrentResolve]
[BrowserViewController.m]--[setTimer:]
[AppController.m]--[browserViewController:didResolveInstance:]
the netService didResolveInstance is: <NSNetService 0x4e0f2a0> local. _witap._tcp. “DWJ”的 iPad
[AppController.m]--[openStreams]
[AppController.m]--[stream:handleEvent:]
case open completed
[AppController.m]--[destroyPicker]
[Picker.m]--[dealloc]
[BrowserViewController.m]--[dealloc]
[BrowserViewController.m]--[stopCurrentResolve]
[BrowserViewController.m]--[setTimer:]
[TCPServer.m]--[dealloc]
[TCPServer.m]--[stop]
[TCPServer.m]--[disableBonjour]
about to call NetService:stop
[AppController.m]--[stream:handleEvent:]
case open completed
[AppController.m]--[destroyPicker]
show the message game started
[AppController.m]--[stream:handleEvent:]
case there is no corresponding case match this event
下面是点击一次本机的TapView执行如下
2011-12-02 15:26:45.055 WiTap[6260:40b] [/Users/administrator/Downloads/WiTap/TapView.m]--[touchesBegan:withEvent:]
2011-12-02 15:26:45.056 WiTap[6260:40b] [/Users/administrator/Downloads/WiTap/TapView.m]--[touchDown:]
2011-12-02 15:26:45.057 WiTap[6260:40b] [/Users/administrator/Downloads/WiTap/AppController.m]--[activateView:]
2011-12-02 15:26:45.058 WiTap[6260:40b] [/Users/administrator/Downloads/WiTap/AppController.m]--[send:]
2011-12-02 15:26:45.059 WiTap[6260:40b] [/Users/administrator/Downloads/WiTap/AppController.m]--[stream:handleEvent:]
2011-12-02 15:26:45.059 WiTap[6260:40b] case there is no corresponding case match this event
2011-12-02 15:26:45.135 WiTap[6260:40b] [/Users/administrator/Downloads/WiTap/TapView.m]--[touchesEnded:withEvent:]
2011-12-02 15:26:45.135 WiTap[6260:40b] [/Users/administrator/Downloads/WiTap/TapView.m]--[localTouchUp]
2011-12-02 15:26:45.136 WiTap[6260:40b] [/Users/administrator/Downloads/WiTap/TapView.m]--[touchUp:]
2011-12-02 15:26:45.137 WiTap[6260:40b] [/Users/administrator/Downloads/WiTap/AppController.m]--[deactivateView:]
2011-12-02 15:26:45.137 WiTap[6260:40b] [/Users/administrator/Downloads/WiTap/AppController.m]--[send:]
2011-12-02 15:26:45.139 WiTap[6260:40b] [/Users/administrator/Downloads/WiTap/AppController.m]--[stream:handleEvent:]
2011-12-02 15:26:45.140 WiTap[6260:40b] case there is no corresponding case match this event
下面是点击一次远程的TapView执行如下
2011-12-02 15:29:00.261 WiTap[6260:40b] [/Users/administrator/Downloads/WiTap/AppController.m]--[stream:handleEvent:]
2011-12-02 15:29:00.262 WiTap[6260:40b] case has bytes available
2011-12-02 15:29:00.263 WiTap[6260:40b] [/Users/administrator/Downloads/WiTap/TapView.m]--[touchDown:]
2011-12-02 15:29:00.344 WiTap[6260:40b] [/Users/administrator/Downloads/WiTap/AppController.m]--[stream:handleEvent:]
2011-12-02 15:29:00.344 WiTap[6260:40b] case has bytes available
2011-12-02 15:29:00.345 WiTap[6260:40b] [/Users/administrator/Downloads/WiTap/TapView.m]--[touchUp:]
真机退出程序后,模拟器执行
2011-12-05 10:55:01.545 WiTap[350:40b] [/Users/administrator/Downloads/WiTap/AppController.m]--[stream:handleEvent:]
2011-12-05 10:55:01.546 WiTap[350:40b] case has bytes available
2011-12-05 10:55:01.547 WiTap[350:40b] [/Users/administrator/Downloads/WiTap/AppController.m]--[stream:handleEvent:]
2011-12-05 10:55:01.547 WiTap[350:40b] case end encountered
2011-12-05 10:55:01.548 WiTap[350:40b] [/Users/administrator/Downloads/WiTap/TapView.m]--[touchUp:]
2011-12-05 10:55:01.548 WiTap[350:40b] [/Users/administrator/Downloads/WiTap/TapView.m]--[touchUp:]
2011-12-05 10:55:01.549 WiTap[350:40b] [/Users/administrator/Downloads/WiTap/TapView.m]--[touchUp:]
2011-12-05 10:55:01.550 WiTap[350:40b] [/Users/administrator/Downloads/WiTap/TapView.m]--[touchUp:]
2011-12-05 10:55:01.550 WiTap[350:40b] [/Users/administrator/Downloads/WiTap/TapView.m]--[touchUp:]
2011-12-05 10:55:01.551 WiTap[350:40b] [/Users/administrator/Downloads/WiTap/TapView.m]--[touchUp:]
2011-12-05 10:55:01.551 WiTap[350:40b] [/Users/administrator/Downloads/WiTap/TapView.m]--[touchUp:]
2011-12-05 10:55:01.552 WiTap[350:40b] [/Users/administrator/Downloads/WiTap/TapView.m]--[touchUp:]
2011-12-05 10:55:01.553 WiTap[350:40b] [/Users/administrator/Downloads/WiTap/TapView.m]--[touchUp:]
模拟器点击alterView的continue按钮后执行
2011-12-05 10:55:41.627 WiTap[350:40b] [/Users/administrator/Downloads/WiTap/AppController.m]--[alertView:clickedButtonAtIndex:]
2011-12-05 10:55:41.628 WiTap[350:40b] [/Users/administrator/Downloads/WiTap/AppController.m]--[setup]
余下过程和模拟器刚启动是执行的一样
(二)真机和模拟器一起调试,模拟器作为连接响应方时的执行过程
以下过程是真机先启动,模拟器后启动的时候,模拟器执行的流程
2011-12-05 11:02:26.410 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/AppController.m]--[applicationDidFinishLaunching:]
2011-12-05 11:02:26.416 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/AppController.m]--[setup]
2011-12-05 11:02:26.417 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/TCPServer.m]--[init]
2011-12-05 11:02:26.418 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/TCPServer.m]--[start:]
2011-12-05 11:02:26.419 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/TCPServer.m]--[bonjourTypeFromIdentifier:]
2011-12-05 11:02:26.420 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/TCPServer.m]--[enableBonjourWithDomain:applicationProtocol:name:]
2011-12-05 11:02:26.422 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/AppController.m]--[presentPicker:]
2011-12-05 11:02:26.422 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/TCPServer.m]--[bonjourTypeFromIdentifier:]
2011-12-05 11:02:26.423 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Picker.m]--[initWithFrame:type:]
2011-12-05 11:02:26.424 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/BrowserViewController.m]--[initWithTitle:showDisclosureIndicators:showCancelButton:]
2011-12-05 11:02:26.425 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/BrowserViewController.m]--[searchForServicesOfType:inDomain:]
2011-12-05 11:02:26.425 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/BrowserViewController.m]--[stopCurrentResolve]
2011-12-05 11:02:26.426 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/BrowserViewController.m]--[setTimer:]
2011-12-05 11:02:26.429 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/BrowserViewController.m]--[numberOfSectionsInTableView:]
2011-12-05 11:02:26.430 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/BrowserViewController.m]--[tableView:numberOfRowsInSection:]
2011-12-05 11:02:26.430 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/BrowserViewController.m]--[searchingForServicesString]
2011-12-05 11:02:26.432 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Picker.m]--[setDelegate:]
2011-12-05 11:02:26.433 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Picker.m]--[setGameName:]
2011-12-05 11:02:26.433 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/BrowserViewController.m]--[setOwnName:]
2011-12-05 11:02:26.441 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/BrowserViewController.m]--[netServiceBrowser:didFindService:moreComing:]
2011-12-05 11:02:26.444 WiTap[422:40b] the service is: <NSNetService 0x4e3a3f0> local. _witap._tcp. “DWJ”的 iPad
2011-12-05 11:02:26.445 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/BrowserViewController.m]--[sortAndUpdateUI]
2011-12-05 11:02:26.446 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/BrowserViewController.m]--[numberOfSectionsInTableView:]
2011-12-05 11:02:26.447 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/BrowserViewController.m]--[tableView:numberOfRowsInSection:]
2011-12-05 11:02:26.448 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/BrowserViewController.m]--[tableView:cellForRowAtIndexPath:]
2011-12-05 11:02:27.159 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/TCPServer.m]--[netServiceDidPublish:]
2011-12-05 11:02:27.160 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/AppController.m]--[serverDidEnableBonjour:withName:]
2011-12-05 11:02:27.161 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/AppController.m]--[presentPicker:]
2011-12-05 11:02:27.162 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Picker.m]--[setGameName:]
2011-12-05 11:02:27.162 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/BrowserViewController.m]--[setOwnName:]
2011-12-05 11:02:27.163 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/BrowserViewController.m]--[numberOfSectionsInTableView:]
2011-12-05 11:02:27.163 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/BrowserViewController.m]--[tableView:numberOfRowsInSection:]
2011-12-05 11:02:27.164 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/BrowserViewController.m]--[tableView:cellForRowAtIndexPath:]
2011-12-05 11:02:27.409 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/BrowserViewController.m]--[netServiceBrowser:didFindService:moreComing:]
2011-12-05 11:02:27.410 WiTap[422:40b] the service is: <NSNetService 0x4e3fee0> local. _witap._tcp. dingwenjie
2011-12-05 11:02:27.411 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/BrowserViewController.m]--[sortAndUpdateUI]
2011-12-05 11:02:27.411 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/BrowserViewController.m]--[numberOfSectionsInTableView:]
2011-12-05 11:02:27.412 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/BrowserViewController.m]--[tableView:numberOfRowsInSection:]
2011-12-05 11:02:27.413 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/BrowserViewController.m]--[tableView:cellForRowAtIndexPath:]
2011-12-05 11:02:27.425 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/BrowserViewController.m]--[initialWaitOver:]
以下过程是真机点击服务列表后,模拟器执行的流程
2011-12-05 11:03:49.417 WiTap[422:40b]
*************TCPServerAcceptCallBack is runing*******************
2011-12-05 11:03:49.418 WiTap[422:40b] the server in call back is: <TCPServer = 0x04E35CE0 | port 49885 | netService = <NSNetService 0x4b212e0> local. _witap._tcp. dingwenjie>
2011-12-05 11:03:49.418 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/TCPServer.m]--[handleNewConnectionFromAddress:inputStream:outputStream:]
2011-12-05 11:03:49.419 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/AppController.m]--[didAcceptConnectionForServer:inputStream:outputStream:]
2011-12-05 11:03:49.420 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/TCPServer.m]--[dealloc]
2011-12-05 11:03:49.421 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/TCPServer.m]--[stop]
2011-12-05 11:03:49.421 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/TCPServer.m]--[disableBonjour]
2011-12-05 11:03:49.422 WiTap[422:40b] about to call NetService:stop
2011-12-05 11:03:49.423 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/AppController.m]--[openStreams]
2011-12-05 11:03:49.424 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/AppController.m]--[stream:handleEvent:]
2011-12-05 11:03:49.424 WiTap[422:40b] case open completed
2011-12-05 11:03:49.425 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/AppController.m]--[destroyPicker]
2011-12-05 11:03:49.426 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Picker.m]--[dealloc]
2011-12-05 11:03:49.426 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/BrowserViewController.m]--[dealloc]
2011-12-05 11:03:49.427 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/BrowserViewController.m]--[stopCurrentResolve]
2011-12-05 11:03:49.427 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/Networking/BrowserViewController.m]--[setTimer:]
2011-12-05 11:03:49.430 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/AppController.m]--[stream:handleEvent:]
2011-12-05 11:03:49.431 WiTap[422:40b] case open completed
2011-12-05 11:03:49.431 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/AppController.m]--[destroyPicker]
2011-12-05 11:03:49.432 WiTap[422:40b] show the message game started
2011-12-05 11:03:49.499 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/AppController.m]--[stream:handleEvent:]
2011-12-05 11:03:49.508 WiTap[422:40b] case there is no corresponding case match this event
以下过程是真机点击一个TapView的时候,模拟器执行的流程
2011-12-05 11:04:39.845 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/AppController.m]--[stream:handleEvent:]
2011-12-05 11:04:39.846 WiTap[422:40b] case has bytes available
2011-12-05 11:04:39.847 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/TapView.m]--[touchDown:]
2011-12-05 11:04:39.866 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/AppController.m]--[stream:handleEvent:]
2011-12-05 11:04:39.867 WiTap[422:40b] case has bytes available
2011-12-05 11:04:39.868 WiTap[422:40b] [/Users/administrator/Downloads/WiTap/TapView.m]--[touchUp:]
呵呵,勉强地完成了这个系列,感觉对于长系列的东西我还是缺乏控制力呀,感觉讲的越到后来越不清楚了……
(能力有限,文中可能会有不对的地方,希望大家指教。谢谢!!)