iOS数据、界面分开设计模式遇到的一个问题
2012-09-14 10:43
477 查看
我们习惯在开发中把数据和界面分开实现,这种方式比较好,只需要在数据和界面中同时依赖一个数据结构即可,这种做法对于解藕是一个不错的方式。
但是有一些细节的地方可能会导致我们遇到一些很难查找的bug,比如我们之前遇到的一个问题,现在分享给大家。
先来描述一下问题:我们在UITableView中加入了一个向下拖动刷新数据的控件,控件是EGORefreshTableHeaderView。拖动后,我们就使用ASIHttpRequest刷新数据,但是在拖动幅度大一些时,ASIHttpRequest请求发出后就直接崩溃了,而且看栈也看不出崩在哪。
数据请求代码如下:
猜测调试过程如下:
1)开始猜测问题是EGORefreshTableHeaderView大幅拖动导致的,于是把ASIHttpRequest请求数据注释掉,再次大幅拖动,程序没崩。
2)那问题一定出在ASIHttpRequest请求部分,猜测会不会是请求在子线程中做的,导致的问题,调试一下,发现请求还是在主线程中,所以也排除了这种情况。
3)一开始一直以为是ASIHttpRequest出的问题,所以精力一直放在他上面。但是后来调了1个小时,查了ASIHttpRequest的使用说明,也没查到什么疑点。
4)实在是没办法了,祭出屠龙宝刀:开始代码分段注释,运行看结果。问题出在
这段,运行,结果正常了,http请求也能收到返回的结果了,天哪,要是早点采用这种方法,也就不用之前尝试的1个小时了。开始分析为什么,newsDataArray前面说了,这个数据是会通过
看完这些,我也知道问题出在什么地方了,我们知道,在UITableView中,在用户拖动cell,有cell 的indexPath发生变化时,就会触发这个函数:
这么来的,这里面全是使用的指针拷贝,原来问题就是这个:浅拷贝,先来解释一下深拷贝和浅拷贝:
(1)深拷贝,就是新拷贝一块内存交给对象使用。会拷贝整个数据到新的地址,老的拷贝源改变和目标地址的数据就无关了。
(2)浅拷贝,就是觉得拷贝内存太浪费,直接给你我的地址吧。当然这个地址和拷贝源相同,只要拷贝源发生改变,这个目标地址中的数据也会变化。
问题就明显了[newsDataArray removeAllObjects];导致了UITableView中的数据源发生变化,而大幅度拉动,导致了UITableView中数据刷新,进入
问题解决,收工。
但是有一些细节的地方可能会导致我们遇到一些很难查找的bug,比如我们之前遇到的一个问题,现在分享给大家。
先来描述一下问题:我们在UITableView中加入了一个向下拖动刷新数据的控件,控件是EGORefreshTableHeaderView。拖动后,我们就使用ASIHttpRequest刷新数据,但是在拖动幅度大一些时,ASIHttpRequest请求发出后就直接崩溃了,而且看栈也看不出崩在哪。
数据请求代码如下:
- (void)startGetNewsListData { //newsDataArray是一个成员变量,用于取到数据后用于postNotificationName,给UITableView使用到 if (nil !=newsDataArray &&newsDataArray.count >0) { [newsDataArrayremoveAllObjects]; } NSString *strURL = @"*****";//此处需要填入url的地址字符串 NSURL *url = [NSURLURLWithString:strURL]; ASIHTTPRequest *request = [ASIHTTPRequestrequestWithURL:url]; //设定委托,委托自己实现异步请求方法 [request setDelegate : self ]; // 开始异步请求 [requeststartAsynchronous ];//执行完这句后,就直接崩溃了 //[request release]; } - ( void )requestFinished:( ASIHTTPRequest *)request { NSString *strRequest = [request responseString]; SBJsonParser *parser = [[SBJsonParseralloc]init]; NSDictionary *json = [parser objectWithString:strRequest error:nil]; int nCounts = [[json objectForKey:@"counts"]intValue]; NSArray *activities = [json objectForKey:@"news"]; for (int i =0; i< nCounts; i++) { NSDictionary *dictSummary = [activitiesobjectAtIndex:i]; NewsData *data = [[NewsDataalloc]init]; data.ID = [dictSummary objectForKey:@"id"]; ......//填入NewsData的各成员变量 [newsDataArray addObject:data]; [data release]; } ......//其他逻辑 [[NSNotificationCenterdefaultCenter]postNotificationName:@"GetNewsListDataDone"object:newsDataArray]; }
猜测调试过程如下:
1)开始猜测问题是EGORefreshTableHeaderView大幅拖动导致的,于是把ASIHttpRequest请求数据注释掉,再次大幅拖动,程序没崩。
2)那问题一定出在ASIHttpRequest请求部分,猜测会不会是请求在子线程中做的,导致的问题,调试一下,发现请求还是在主线程中,所以也排除了这种情况。
3)一开始一直以为是ASIHttpRequest出的问题,所以精力一直放在他上面。但是后来调了1个小时,查了ASIHttpRequest的使用说明,也没查到什么疑点。
4)实在是没办法了,祭出屠龙宝刀:开始代码分段注释,运行看结果。问题出在
- (void)startGetNewsListData函数,所以从这边开始:注释 if (nil != newsDataArray && newsDataArray.count > 0) { [newsDataArray removeAllObjects]; }
这段,运行,结果正常了,http请求也能收到返回的结果了,天哪,要是早点采用这种方法,也就不用之前尝试的1个小时了。开始分析为什么,newsDataArray前面说了,这个数据是会通过
[[NSNotificationCenter defaultCenter] postNotificationName:@"GetNewsListDataDone" object:newsDataArray]; 发送,给UITableView中使用,看接收称处的代码: ...... [[NSNotificationCenterdefaultCenter]addObserver:selfselector:@selector(onGetNewsListDataSuccess:)name:@"GetNewsListDataDone"object:nil]; ...... - (void)onGetNewsListDataSuccess:(NSNotification*)notify { NSMutableArray *receiveArray = [notify object]; ...... NSInteger nNewsCount = receiveArray.count; if (nNewsCount >0) { m_arrNews = receiveArray;//可以看到下面使用这个成员变量m_arrNews } [m_TableView reloadData]; ...... } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString* strCellIdentifier =@"NewsCellIdentifier"; NewsListCell* cell = (NewsListCell *)[tableViewdequeueReusableCellWithIdentifier:strCellIdentifier]; if (cell == nil) { ...... } NSInteger row = indexPath.row; if (m_arrNews) { //可以看到UITableView中的数据就是使用的m_arrNews NewsData* data = (NewsData *)[m_arrNewsobjectAtIndex:row]; cell.Title = data.Title; ...... } ...... return cell; }
看完这些,我也知道问题出在什么地方了,我们知道,在UITableView中,在用户拖动cell,有cell 的indexPath发生变化时,就会触发这个函数:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)这个函数中我们用到了m_arrNews,而m_arrNews又是通过 NSMutableArray *receiveArray = [notify object]; ...... m_arrNews = receiveArray;
这么来的,这里面全是使用的指针拷贝,原来问题就是这个:浅拷贝,先来解释一下深拷贝和浅拷贝:
(1)深拷贝,就是新拷贝一块内存交给对象使用。会拷贝整个数据到新的地址,老的拷贝源改变和目标地址的数据就无关了。
(2)浅拷贝,就是觉得拷贝内存太浪费,直接给你我的地址吧。当然这个地址和拷贝源相同,只要拷贝源发生改变,这个目标地址中的数据也会变化。
问题就明显了[newsDataArray removeAllObjects];导致了UITableView中的数据源发生变化,而大幅度拉动,导致了UITableView中数据刷新,进入
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *),数据失效,导致崩溃,那解决问题也很简单,使用深拷贝就可以了。 - (void)onGetNewsListDataSuccess:(NSNotification*)notify { //NSMutableArray *receiveArray = [notify object];改成 NSMutableArray *receiveArray = [[NSArrayalloc]initWithArray:[notifyobject]]; ...... NSInteger nNewsCount = receiveArray.count; if (nNewsCount >0) { m_arrNews = receiveArray;//可以看到下面使用这个成员变量m_arrNews } [m_TableViewreloadData]; ...... }
问题解决,收工。
相关文章推荐
- 在探索java i/o的Decorator模式时,遇到的一个问题.
- 基本上,把switch,用设计模式代替,肯定是bug和过度设计。想想,本来修改一个文件几行代码可以解决的问题,变成修改3-6个类才能实现一样的功能。不是傻是什么?
- winform设计一个登录界面和修改密码的界面-自动切换窗体(问题[已解] 望一起讨论)(技术改变世界-cnblog)
- JAVA GUI设计中遇到的一个小问题
- 前端开发在IOS端遇到的一个诡异问题(Delegate 失效)
- SSDP协议下STA模式和softAP模式间切换时遇到的数据收发问题
- 写一个之前遇到的问题,遇到ios项目中包含idfa的解决办法
- C# 操作数据导出到Excel遇到的一个小问题
- winform设计一个登录界面和修改密码的界面-自动切换窗体(问题[已解] 望一起讨论)(技术改变世界-cnblog)
- 处理数据的时候遇到的一个小问题
- iOS 使用协议委托遇到的一个小问题
- 数据是信息的载体 当遇到由于设计不严谨造成信息没有被完全承载 造成的区分度不够问题 解决方法
- php与iOS POST传送数据时可能遇到的问题
- 设计模式-生产者消费者模式 常见场景: 某个模块负责产生数据,这些数据由另一个模块来负责处理。产生数据的模块,就形象地称为生产者;而处理数据的模块,就称为消费者。 该模式还需要有一个缓冲区处于生
- 关于Android7.0系统使用webview遇到的一个问题(二级跳转后界面空白)
- 自己遇到的一个单例模式的问题记录
- 工作中遇到的一个SqlServer2000中大数据量表的检索问题
- 一个采取数据后的预警通知的设计----观察者模式的变通
- 遇到一个moodle平台设计问题
- 使用SSRS设计报表布局时遇到的一个奇怪问题