《开源中国iOS客户端学习》续写前系列博客 http://blog.csdn.net/column/details/xfzl-kykhd.html
说到这款开源软件就得提到她的娘家了--开源中国社区:
开源中国社区简介:开源中国 www.oschina.net 成立于2008年8月,是目前中国最大的开源技术社区。传播开源的理念,推广开源项目,为 IT 开发者提供了一个发现、使用、并交流开源技术的平台。目前开源中国社区已收录超过两万款开源软件。开源中国社区在移动设备上做了客户端以后,将他们源代码做了开源分享,让我们初学者有机会看到大牛们是怎样设计软件怎么写的代码,拿到源码也有一两个月了,只是草草的看了一遍,现在想深入的去学习一遍,分析一个完整工程代码,希望能收获些东西;
开源中国客户端上用到的东西很多,基本涵盖了我们做iOS应用开发需要学的全部内容,软件里面有很多特效用的是别人封装好的第三方类库,比如下拉刷新、异步加载图片、XML解析、正则表达式等,采用了经典的MVC设计模式,也许会觉得界面不如别的软件界面美观,但是却很值得我们正在学习iOS的同学去学习;
开源中国客户端界面
项目目录导航视图
项目目录简单解析:
1、AFNetwork --- 通用网络库
2、GCDiscreetNotificationView --- 顶部弹出并会自动消失的通知栏
3、Thread --- 后台线程对象,处理后台发送带图片的动弹
4、SoftwareGroup --- 所有软件索引页以及软件分组页
5、Friends --- 好友列表页,包括粉丝与关注者
6、Search --- 搜索页
7、Favorite --- 收藏页
8、MBHUD --- 载入提示控件
9、FTColor --- 富文本显示控件
10、EGOImageLoading --- 异步图像控件
11、User --- 其他用户个人专页以及登陆用户专页
12、Comment --- 评论列表页以及发表评论页
13、AsyncImg --- 异步图像控件,总要用于列表中用户头像加载
、Setting --- 登录,注销以及关于我们
15Profile --- 动态页,发表留言,以及对话气泡 问答
16News --- 新闻,问答的列表以及所有类型的文章详情页
17、Tweet --- 动弹 列表,发表动弹以及动弹详情
18、Helper --- 项目辅助类
19、TBXML --- xml解析,反序列化所有API返回的XML字符串
20、ASIHttp --- 另一种网络库,负责用户登陆以及发送带图片的动弹
21、Model --- 项目所有的实体对象
22、Resource --- 项目资源
Model 目录的子对象:
Model
├ Tweet 动弹列表单元,也用于动弹详情
├ News 新闻列表单元
├ Post 问答列表单元
├ Message 留言列表单元
├ Activity 动态列表单元
├ Config 程序配置设置
├ SingleNews 新闻详情
├ SinglePostDetail 问答详情
└ Comment 评论列表单元
└ Software 软件详情
└ Blog 博客详情
└ Favorite 收藏列表单元
└ SearchResult 搜索结果列表单元
└ Friend 好友列表单元
└ SoftwareCatalog 软件分类列表单元
└ SoftwareUnit 软件列表单元
└ BlogUnit 博客列表单元
项目的功能流程
1、APP启动流程
OSAppDelegate 的启动方法中,声明一个 UITabBarController,然后依次将
NewsBase
PostBase——我的
TweetBase2 动弹
ProfileBase ——问答
SettingView
填充到5个UITabItem里
2、ipa文件生成流程
1,在OSX系统上启动iTunes程序
2,启动Xcode,将项目中的 OSChina/Products/oschina.app 按住command键然后用鼠标拖放到iTunes的应用程序栏目
3,然后在iTunes程序中右键点击"开源中国"图标,在弹出的的菜单中选择"在Finder中显示",这样你就看到ipa文件的路径了。
开源中国客户端源码 GitHub : https://github.com/oschina
CSDN : http://download.csdn.net/detail/duxinfeng2010/4877544
分类: 菜鸟学iOS的笔记
2012-12-12 21:33 10052人阅读 评论(13) 收藏 举报
pch全称是“precompiled header”,也就是提高编译器编译速度。我们知道当我们修改一个工程中某个文件代码时候,编译器并不是重新编译所有所有文件,而是编译改动过文件的,假如pch中某个文件修改了,那么pch整个文件里包含的的其他文件也会重新编译一次,这样就会消耗大量时间,所以它里面添加的文件最好是是很少变动或不变动的头文件或者是预编译的代码片段;
在新建一个工程时,pch后缀文件里代码是
[cpp] view plaincopy
- #import <Availability.h>
- #ifndef __IPHONE_4_0
- #warning "This project uses features only available in iOS SDK 4.0 and later."
- #endif
- #ifdef __OBJC__
- #import <UIKit/UIKit.h>
- #import <Foundation/Foundation.h>
- #endif
或许你会觉得这预编译代码很少,但是你可以查看一下UIKit.h的定义文件中
[cpp] view plaincopy
- //
- // UIKit.h
- // UIKit
- //
- // Copyright (c) 2005-2011, Apple Inc. All rights reserved.
- //
- #import <UIKit/UIKitDefines.h>
- #import <UIKit/UIAccelerometer.h>
- #import <UIKit/UIAccessibility.h>
- #import <UIKit/UIActivityIndicatorView.h>
- #import <UIKit/UIAlert.h>
- #import <UIKit/UIApplication.h>
- #import <UIKit/UIBarButtonItem.h>
- #import <UIKit/UIBarItem.h>
- #import <UIKit/UIBezierPath.h>
- #import <UIKit/UIButton.h>
- #import <UIKit/UIColor.h>
- #import <UIKit/UIControl.h>
- #import <UIKit/UIDataDetectors.h>
- #import <UIKit/UIDatePicker.h>
- #import <UIKit/UIDevice.h>
- #import <UIKit/UIDocument.h>
- #import <UIKit/UIDocumentInteractionController.h>
- #import <UIKit/UIEvent.h>
- #import <UIKit/UIFont.h>
- #import <UIKit/UIGeometry.h>
- #import <UIKit/UIGestureRecognizer.h>
- #import <UIKit/UIGraphics.h>
- #import <UIKit/UIImage.h>
- #import <UIKit/UIImagePickerController.h>
- #import <UIKit/UIImageView.h>
- #import <UIKit/UIInterface.h>
- #import <UIKit/UILabel.h>
- #import <UIKit/UILocalNotification.h>
- #import <UIKit/UILocalizedIndexedCollation.h>
- #import <UIKit/UILongPressGestureRecognizer.h>
- #import <UIKit/UIManagedDocument.h>
- #import <UIKit/UIMenuController.h>
- #import <UIKit/UINavigationBar.h>
- #import <UIKit/UINavigationController.h>
- #import <UIKit/UINib.h>
- #import <UIKit/UINibDeclarations.h>
- #import <UIKit/UINibLoading.h>
- #import <UIKit/UIPageControl.h>
- #import <UIKit/UIPageViewController.h>
- #import <UIKit/UIPanGestureRecognizer.h>
- #import <UIKit/UIPasteboard.h>
- #import <UIKit/UIPickerView.h>
- #import <UIKit/UIPinchGestureRecognizer.h>
- #import <UIKit/UIPopoverController.h>
- #import <UIKit/UIPopoverBackgroundView.h>
- #import <UIKit/UIPrintError.h>
- #import <UIKit/UIPrintFormatter.h>
- #import <UIKit/UIPrintInfo.h>
- #import <UIKit/UIPrintInteractionController.h>
- #import <UIKit/UIPrintPageRenderer.h>
- #import <UIKit/UIPrintPaper.h>
- #import <UIKit/UIProgressView.h>
- #import <UIKit/UIReferenceLibraryViewController.h>
- #import <UIKit/UIResponder.h>
- #import <UIKit/UIRotationGestureRecognizer.h>
- #import <UIKit/UIScreen.h>
- #import <UIKit/UIScreenMode.h>
- #import <UIKit/UIScrollView.h>
- #import <UIKit/UISearchBar.h>
- #import <UIKit/UISearchDisplayController.h>
- #import <UIKit/UISegmentedControl.h>
- #import <UIKit/UISlider.h>
- #import <UIKit/UISplitViewController.h>
- #import <UIKit/UIStepper.h>
- #import <UIKit/UIStoryboard.h>
- #import <UIKit/UIStoryboardPopoverSegue.h>
- #import <UIKit/UIStoryboardSegue.h>
- #import <UIKit/UIStringDrawing.h>
- #import <UIKit/UISwipeGestureRecognizer.h>
- #import <UIKit/UISwitch.h>
- #import <UIKit/UITabBar.h>
- #import <UIKit/UITabBarController.h>
- #import <UIKit/UITabBarItem.h>
- #import <UIKit/UITableView.h>
- #import <UIKit/UITableViewCell.h>
- #import <UIKit/UITableViewController.h>
- #import <UIKit/UITapGestureRecognizer.h>
- #import <UIKit/UITextField.h>
- #import <UIKit/UITextInput.h>
- #import <UIKit/UITextInputTraits.h>
- #import <UIKit/UITextView.h>
- #import <UIKit/UIToolbar.h>
- #import <UIKit/UITouch.h>
- #import <UIKit/UIVideoEditorController.h>
- #import <UIKit/UIView.h>
- #import <UIKit/UIViewController.h>
- #import <UIKit/UIWebView.h>
- #import <UIKit/UIWindow.h>
这些不少了吧,工程每次运行都编译是不是很费时间,这些是苹果公司内部定义的标准头文件,我们不能也没有权限修改这些头文件定义内容,所以,当放到pch文件中会加速编译过程;
再来看看我们开源中国iOS客户端pch文件
[cpp] view plaincopy
- //
- // Prefix header for all source files of the 'oschina' target in the 'oschina' project
- //
- #import <Availability.h>
- #ifndef __IPHONE_4_0
- #warning "This project uses features only available in iOS SDK 4.0 and later."
- #endif
- #ifdef __OBJC__
- #import <UIKit/UIKit.h>
- #import <Foundation/Foundation.h>
- #import <CoreData/CoreData.h>
- #import <QuartzCore/QuartzCore.h>
- //添加的预编译
- #import "ASIHTTPRequest.h"
- #import "ASIFormDataRequest.h"
- #import "ASIHTTPRequestDelegate.h"
- #import "ASIHTTPRequestConfig.h"
- #import "TBXML.h"
- #import "TBXML+HTTP.h"
- #import "TBXML+Compression.h"
- #import "Config.h"
- #import "EGORefreshTableHeaderView.h"
- #import "DataSingleton.h"
- #import "ImgRecord.h"
- #import "IconDownloader.h"
- #import "MBProgressHUD.h"
- #import "GCDiscreetNotificationView.h"
- #import "NdUncaughtExceptionHandler.h"
- #import "JSNotifier.h"
- #import "AFOSCClient.h"
- #import "AFHTTPRequestOperation.h"
- #import "AFXMLRequestOperation.h"
- //api定义
- #define api_news_list @"http://www.oschina.net/action/api/news_list"
- #define api_news_detail @"http://www.oschina.net/action/api/news_detail"
- #define api_post_list @"http://www.oschina.net/action/api/post_list"
- #define api_post_detail @"http://www.oschina.net/action/api/post_detail"
- #define api_post_pub @"http://www.oschina.net/action/api/post_pub"
- #define api_tweet_list @"http://www.oschina.net/action/api/tweet_list"
- #define api_tweet_detail @"http://www.oschina.net/action/api/tweet_detail"
- #define api_tweet_delete @"http://www.oschina.net/action/api/tweet_delete"
- #define api_tweet_pub @"http://www.oschina.net/action/api/tweet_pub"
- #define api_active_list @"http://www.oschina.net/action/api/active_list"
- #define api_message_list @"http://www.oschina.net/action/api/message_list"
- #define api_message_delete @"http://www.oschina.net/action/api/message_delete"
- #define api_message_pub @"http://www.oschina.net/action/api/message_pub"
- #define api_comment_list @"http://www.oschina.net/action/api/comment_list"
- #define api_comment_pub @"http://www.oschina.net/action/api/comment_pub"
- #define api_comment_reply @"http://www.oschina.net/action/api/comment_reply"
- #define api_comment_delete @"http://www.oschina.net/action/api/comment_delete"
- #define api_login_validate @"https://www.oschina.net/action/api/login_validate"
- #define api_user_info @"http://www.oschina.net/action/api/user_info"
- #define api_user_information @"http://www.oschina.net/action/api/user_information"
- #define api_user_updaterelation @"http://www.oschina.net/action/api/user_updaterelation"
- #define api_notice_clear @"http://www.oschina.net/action/api/notice_clear"
- #define api_software_detail @"http://www.oschina.net/action/api/software_detail"
- #define api_blog_detail @"http://www.oschina.net/action/api/blog_detail"
- #define api_favorite_list @"http://www.oschina.net/action/api/favorite_list"
- #define api_favorite_add @"http://www.oschina.net/action/api/favorite_add"
- #define api_favorite_delete @"http://www.oschina.net/action/api/favorite_delete"
- #define api_user_notice @"http://www.oschina.net/action/api/user_notice"
- #define api_search_list @"http://www.oschina.net/action/api/search_list"
- #define api_friends_list @"http://www.oschina.net/action/api/friends_list"
- #define api_softwarecatalog_list @"http://www.oschina.net/action/api/softwarecatalog_list"
- #define api_software_list @"http://www.oschina.net/action/api/software_list"
- #define api_softwaretag_list @"http://www.oschina.net/action/api/softwaretag_list"
- #define api_blogcomment_list @"http://www.oschina.net/action/api/blogcomment_list"
- #define api_blogcomment_pub @"http://www.oschina.net/action/api/blogcomment_pub"
- #define api_my_information @"http://www.oschina.net/action/api/my_information"
- #define api_blogcomment_delete @"http://www.oschina.net/action/api/blogcomment_delete"
- #define api_userblog_delete @"http://www.oschina.net/action/api/userblog_delete"
- #define api_userblog_list @"http://www.oschina.net/action/api/userblog_list"
- #define api_blog_list @"http://www.oschina.net/action/api/blog_list"
- #define api_userinfo_update @"http://www.oschina.net/action/api/portrait_update"
- //宏定义 新闻
- #define TweetCellIdentifier @"TweetCellIdentifier"
- #define loadMoreIdentifier @"loadMoreIdentifier"
- #define NewsCellIdentifier @"NewsCellIdentifier"
- #define PostCellIdentifier @"PostCellIdentifier"
- #define MsgCellIdentifier @"MsgCellIdentifier"
- #define MsgUnitCellIdentifier @"MsgUnitCellIdentifier"
- #define ActiveCellIdentifier @"ActiveCellIdentifier"
- #define UserActiveCellIdentifier @"UserActiveCellIdentifier"
- #define ColorActiveCellIdentifier @"ColorActiveCellIdentifier"
- #define RTActiveCellIdentifier @"RTActiveCellIdentifier"
- #define ColorUserActiveCellIdentifier @"ColorUserActiveCellIdentifier"
- #define ProfielCellIdentifier @"ProfielCellIdentifier"
- #define CommentCellIdentifier @"CommentCellIdentifier"
- #define NormalCellIdentifier @"NormalCellIdentifier"
- #define FavoriteCellIdentifier @"FavoriteCellIdentifier"
- #define FriendCellIdentifier @"FriendCellIdentifier"
- #define SoftwareCellIdentifier @"SoftwareCellIdentifier"
- #define SoftwareCatalogIdentifier @"SoftwareCatalogIdentifier"
- #define SettingTableIdentifier @"SettingTableIdentifier"
- #define MyInfoCellIdentifier @"MyInfoCellIdentifier"
- #define MyPortraitCellIdentifier @"MyPortraitCellIdentifier"
- #define loadNext20Tip @"下面 20 项 . . ."
- #define loadingTip @"正在加载 . . ."
- #define networkError @"网络无连接"
- #define noNetworkTip @"网络无连接"
- //消息通知固定字符串
- #define Notification_DetailCommentCount @"Notification_DetailCommentCount"
- #define Notification_NoticeUpdate @"Notification_NoticeUpdate"
- #define Notification_TabClick @"Notification_TabClick"
- //html头部
- #define HTML_Style @"<style>#oschina_title {color: #000000; margin-bottom: 6px; font-weight:bold;}#oschina_title img{vertical-align:middle;margin-right:6px;}#oschina_title a{color:#0D6DA8;}#oschina_outline {color: #707070; font-size: 12px;}#oschina_outline a{color:#0D6DA8;}#oschina_software{color:#808080;font-size:12px}#oschina_body img {max- 300px;}#oschina_body {font-size:16px;max-300px;line-height:24px;} #oschina_body table{max-300px;}#oschina_body pre { font-size:9pt;font-family:Courier New,Arial;border:1px solid #ddd;border-left:5px solid #6CE26C;background:#f6f6f6;padding:5px;}</style>"
- #define HTML_Bottom @"<div style='margin-bottom:60px'/>"
- #define USERAGENT @"OSChina.NET/iOS/5.0"
- #define AppVersion @"1.6.1"
- #ifdef DEBUG
- #define debugLog(...) NSLog(__VA_ARGS__)
- #define debugMethod() NSLog(@"%s", __func__)
- #else
- #define debugLog(...)
- #define debugMethod()
- #endif
- #endif
我们看到有这样些文件也被添加到里面,可能会想难道这些头文件变化不大吗?
[cpp] view plaincopy
- //添加的预编译
- #import "ASIHTTPRequest.h"
- #import "ASIFormDataRequest.h"
- #import "ASIHTTPRequestDelegate.h"
- #import "ASIHTTPRequestConfig.h"
- #import "TBXML.h"
- #import "TBXML+HTTP.h"
- #import "TBXML+Compression.h"
- #import "Config.h"
- #import "EGORefreshTableHeaderView.h"
- #import "DataSingleton.h"
- #import "ImgRecord.h"
- #import "IconDownloader.h"
- #import "MBProgressHUD.h"
- #import "GCDiscreetNotificationView.h"
- #import "NdUncaughtExceptionHandler.h"
- #import "JSNotifier.h"
- #import "AFOSCClient.h"
- #import "AFHTTPRequestOperation.h"
- #import "AFXMLRequestOperation.h"
其实,这些文件特殊之处在于他们都是第三方类库的头文件,第三方类库将一些对象进行高度封装,留下接口,然后我们根据类库接口直接调用就可以,这些第三方类库一般都比iOS原生自带的更加简单易用,比如TBXML解析库,比iOS自带的NSXMLPaser解析器速度功能上都会好一些;
还有一些宏定义都是比较常用方式的宏定义,比如定义的开源中国社区的api接口,这些接口变得当然很少了;
然后就剩下最后面的
[cpp] view plaincopy
- #ifdef DEBUG
- #define debugLog(...) NSLog(__VA_ARGS__)
- #define debugMethod() NSLog(@"%s", __func__)
- #else
- #define debugLog(...)
- #define debugMethod()
- #endif
工程有Debug Version和Release Version,Debug Version是程序开发过程中版本,它包含了所有调试信息,一些常用的NSLog打印日志,在程序调试过程工根据我们设置的调试信息可以看出什么地方出错,我们在运行运行一个小程序的时候,会不会首先就想到进行断点调试呢,应该是首先想着NSLog一下,看看哪个函数方法没执行,看看是不是哪个数组的值没取出来。Release Version是发布版本,不打印NSLog可以加快程序运行速度,减少内存使用。 但是到一个大工程中,会有很多很多这样的NSLog,在我们工程完美运行的时候,发布Release 版本的时候,难道我们去一行行的注释调NSLog吗?假如工程现在原来基础上发布一个version 1.2版本的,我们在修改程序的时候岂不是还把原来注释给取消,那就很麻烦很麻烦了。
所以,此处用到了宏指令
上段代码的意思就是 用宏指令做一个判断,如果DEBUG为真,则编译#ifdef到#endif宏定义,否则编译器就不编译;
这个DEBUG在哪设置呢,
在 "Target > Build Settings > Preprocessor Macros > Debug" 里有一个"DEBUG=1"。
现在我们来做一个测试:
取一个宏指令放到OSAppDelegate.m的application:didFinishLaunchingWithOptions:方法中,并用同一个NSLog做一个对比;
NSLog(@"%s", __func__);
debugMethod();
首先设置为Debug模式下,Product-->Edit Scheme
跳转到这个界面
当我设置Build Configuration成Debug时,打印效果图
当我设置Build Configuration成Release的,打印时效果图
当Run Test Profile Analyze Archive的时候,都可以根据需要设置Debug和Release两个模式运行;
所以我们完全可以用一个宏指令来设置是否打印调试信息;
欢迎转载分享,请注明出处http://blog.csdn.net/duxinfeng2010
开源中国iOS客户端学习——(二)下拉刷新特效EGOTableViewPullRefresh
分类: 菜鸟学iOS的笔记
2012-12-17 12:25 10708人阅读 评论(29) 收藏 举报
打开开源中国iOS客户端应用程序第一步就是加载数据,经常我们在第二次以后打开的时候,我们界面显示的是上一次更新的数据,此时我们想看最新内容就需要去刷新数据加载这些内容,加载需要一个等待过程,如何能让用户在等待过程中不焦急,能够等待这个过程完成,这就需要给用户一个心里安慰,让用户知道该软件正在很努力很努力的执行自己命令,这就需要我们为自己应用程序添加一些特效;
开源中国iOS客户端用到了不少特效,这些特效在当前很多应用软件中都比较流行,基本上这些特效都属于第三方类库,本次想说的是下拉刷新特效,EGOTableViewPullRefresh最开始是在Twitter中使用,最后做了开源,然后很多应用添加这个特效,常作为加载数据时将等待时间作为一个动画来过渡;
下拉刷新类库EGOTableViewPullRefresh资源文件下载地址:
https://github.com/enormego/EGOTableViewPullRefresh/tree/
先这个特效的效果图
在EGOTableViewPullRefresh资源文件中有两个文件,.m和.h文件,还有资源图片,就是下拉刷新箭头
资源图片一共4种色,可以根据喜好选用不同色的箭头,只需在EGORefreshTableHeaderView.m文件中修改一下。按照大小尺寸又可分两种,较大尺寸是用于iPad上使用的。
针对这些第三方类库,我们没必要去深入研究它们内部实现机制原理,只要知道怎么用就可以。不过,看一看别人实现原理,学学别人的方法还是很不错的,了解下人家牛人程序是怎么写的;
EGORefreshTableHeaderView.h
[cpp] view plaincopy
- #import <UIKit/UIKit.h>
- #import <QuartzCore/QuartzCore.h>
- typedef enum{
- EGOOPullRefreshPulling = 0,
- EGOOPullRefreshNormal,
- EGOOPullRefreshLoading,
- } EGOPullRefreshState;
- @protocol EGORefreshTableHeaderDelegate;
- @interface EGORefreshTableHeaderView : UIView {
- id _delegate;
- EGOPullRefreshState _state;
- UILabel *_lastUpdatedLabel;
- UILabel *_statusLabel;
- CALayer *_arrowImage;
- UIActivityIndicatorView *_activityView;
- }
- @property(nonatomic,assign) id <EGORefreshTableHeaderDelegate> delegate;
- - (id)initWithFrame:(CGRect)frame arrowImageName:(NSString *)arrow textColor:(UIColor *)textColor;
- - (void)refreshLastUpdatedDate;
- - (void)egoRefreshScrollViewDidScroll:(UIScrollView *)scrollView;
- - (void)egoRefreshScrollViewDidEndDragging:(UIScrollView *)scrollView;
- - (void)egoRefreshScrollViewDataSourceDidFinishedLoading:(UIScrollView *)scrollView;
- @end
- //定义协议方法
- @protocol EGORefreshTableHeaderDelegate
- //下拉的时候调用此方法
- - (void)egoRefreshTableHeaderDidTriggerRefresh:(EGORefreshTableHeaderView*)view;
- //判断刷新状态情况,正在刷新或者是没刷新
- - (BOOL)egoRefreshTableHeaderDataSourceIsLoading:(EGORefreshTableHeaderView*)view;
- @optional
- //返回刷新时间,回调方法
- - (NSDate*)egoRefreshTableHeaderDataSourceLastUpdated:(EGORefreshTableHeaderView*)view;
- @end
首先是定义了一个枚举类型EGOPullRefreshState表示当前我们操作在哪种状态下,有下拉状态、正常状态、数据加载状态;
@protocol EGORefreshTableHeaderDelegate;表示声明有这个协议,该协议里面声明了一些方法,只要其他的类遵循了这个协议(也就是遵循了它的规定),就可以去实现协议里面方法,协议里的方法是留给遵循这个协议的类去实现的,也是留给外部实现接口;
EGORefreshTableHeaderView成员变量定义两个label用于提示下拉过程所处状态,和显示的刷新时间。定义的CALayer类对象装载显示图片。UIActivityIndicatorView类对象显示一个等待动画;
@property(nonatomic,assign)id <EGORefreshTableHeaderDelegate> delegate;声明一个协议对象;
接着下面的是EGORefreshTableHeaderView类成员函数,用于实现类库中下拉刷新的效果;
最后定义了4个协议方法,其中最后一个协议方法为可选实现;
下面是EGORefreshTableHeaderView.m文件,想说的都在注释里
[cpp] view plaincopy
- #import "EGORefreshTableHeaderView.h"
- #define TEXT_COLOR [UIColor colorWithRed:87.0/255.0 green:108.0/255.0 blue:137.0/255.0 alpha:1.0]
- #define FLIP_ANIMATION_DURATION 0.18f
- //设置的一个私有接口,只能本类来使用
- @interface EGORefreshTableHeaderView (Private)
- - (void)setState:(EGOPullRefreshState)aState;
- @end
- @implementation EGORefreshTableHeaderView
- @synthesize delegate=_delegate;
- //初始化框架属性,
- - (id)initWithFrame:(CGRect)frame arrowImageName:(NSString *)arrow textColor:(UIColor *)textColor {
- if((self = [super initWithFrame:frame])) {
- // self.view自动适应bounds的宽度
- self.autoresizingMask = UIViewAutoresizingFlexibleWidth;
- // self.view背景色和透明度设置
- self.backgroundColor = [UIColor colorWithRed:226.0/255.0 green:231.0/255.0 blue:237.0/255.0 alpha:1.0];
- UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0.0f, frame.size.height - 30.0f, self.frame.size.width, 20.0f)];
- label.autoresizingMask = UIViewAutoresizingFlexibleWidth;
- label.font = [UIFont systemFontOfSize:12.0f];
- label.textColor = textColor;
- // label文本阴影颜色
- label.shadowColor = [UIColor colorWithWhite:0.9f alpha:1.0f];
- label.shadowOffset = CGSizeMake(0.0f, 1.0f);
- label.backgroundColor = [UIColor clearColor];
- label.textAlignment = UITextAlignmentCenter;
- [self addSubview:label];
- _lastUpdatedLabel=label;
- [label release];
- label = [[UILabel alloc] initWithFrame:CGRectMake(0.0f, frame.size.height - 48.0f, self.frame.size.width, 20.0f)];
- label.autoresizingMask = UIViewAutoresizingFlexibleWidth;
- label.font = [UIFont boldSystemFontOfSize:13.0f];
- label.textColor = textColor;
- label.shadowColor = [UIColor colorWithWhite:0.9f alpha:1.0f];
- label.shadowOffset = CGSizeMake(0.0f, 1.0f);
- label.backgroundColor = [UIColor clearColor];
- label.textAlignment = UITextAlignmentCenter;
- [self addSubview:label];
- _statusLabel=label;
- [label release];
- CALayer *layer = [CALayer layer];
- layer.frame = CGRectMake(25.0f, frame.size.height - 65.0f, 30.0f, 55.0f);
- // 设置layer在view上以某种形式适应
- layer.contentsGravity = kCAGravityResizeAspect;
- layer.contents = (id)[UIImage imageNamed:arrow].CGImage;
- // 判断设备版本,因为一些iOS特性是在最后新增的,要求设备配置高一些,所以做一下判断
- #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 40000
- if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
- layer.contentsScale = [[UIScreen mainScreen] scale];
- }
- #endif
- [[self layer] addSublayer:layer];
- _arrowImage=layer;
- UIActivityIndicatorView *view = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
- view.frame = CGRectMake(25.0f, frame.size.height - 38.0f, 20.0f, 20.0f);
- [self addSubview:view];
- _activityView = view;
- [view release];
- [self setState:EGOOPullRefreshNormal];
- }
- return self;
- }
[cpp] view plaincopy
- //初始化当前视图的frame
- - (id)initWithFrame:(CGRect)frame {
- return [self initWithFrame:frame arrowImageName:@"blueArrow.png" textColor:TEXT_COLOR];
- }
- #pragma mark -
- #pragma mark Setters
- //获取最后一次更新的时间
- - (void)refreshLastUpdatedDate {
- if ([_delegate respondsToSelector:@selector(egoRefreshTableHeaderDataSourceLastUpdated:)]) {
- NSDate *date = [_delegate egoRefreshTableHeaderDataSourceLastUpdated:self];
- // NSDateFormatter实例创建字符串,来表示NSDate和NSCalendarDate对象,已预订格式化字符串输出
- [NSDateFormatter setDefaultFormatterBehavior:NSDateFormatterBehaviorDefault];
- NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
- // 设置日期输出格式
- [dateFormatter setDateStyle:NSDateFormatterShortStyle];
- // 设置时间显示格式
- [dateFormatter setTimeStyle:NSDateFormatterShortStyle];
- // _lastUpdatedLabel.text = [NSString stringWithFormat:@"Last Updated: %@", [dateFormatter stringFromDate:date]];
- _lastUpdatedLabel.text = [NSString stringWithFormat:@"最后更新: %@", [dateFormatter stringFromDate:date]];
- // 存储_lastUpdatedLabel.text内容,放到字典中
- [[NSUserDefaults standardUserDefaults] setObject:_lastUpdatedLabel.text forKey:@"EGORefreshTableView_LastRefresh"];
- // 将NSUserDefaults存储数据放到磁盘
- [[NSUserDefaults standardUserDefaults] synchronize];
- } else {
- _lastUpdatedLabel.text = nil;
- }
- }
[cpp] view plaincopy
- - (void)setState:(EGOPullRefreshState)aState{
- switch (aState) {
- /*触摸屏幕下拉状态*/
- case EGOOPullRefreshPulling:
- // _statusLabel.text = NSLocalizedString(@"Release to refresh...", @"Release to refresh status");
- _statusLabel.text = @"松开即可刷新";
- // 设置下拉刷新过程,箭头的图片的一个动画过程
- [CATransaction begin];
- // 动画时间
- [CATransaction setAnimationDuration:FLIP_ANIMATION_DURATION];
- // 下拉刷新箭头一个翻转过程,(M_PI / 180.0)是角度转换为弧度
- _arrowImage.transform = CATransform3DMakeRotation((M_PI / 180.0) * 180.0f, 0.0f, 0.0f, 1.0f);
- // 动画结束
- [CATransaction commit];
- break;
- /*刚开始触摸屏幕准备下拉的时候的状态*/
- case EGOOPullRefreshNormal:
- if (_state == EGOOPullRefreshPulling) {
- [CATransaction begin];
- [CATransaction setAnimationDuration:FLIP_ANIMATION_DURATION];
- _arrowImage.transform = CATransform3DIdentity;
- [CATransaction commit];
- }
- // _statusLabel.text = NSLocalizedString(@"Pull down to refresh...", @"Pull down to refresh status");
- _statusLabel.text = @"下拉可以刷新";
- [_activityView stopAnimating];
- [CATransaction begin];
- // 因为下拉刷新完成好就不需要下拉动画,此时_activityView动画显示
- // 显示事物关闭动画效果 kCFBooleanTrue关闭 kCFBooleanFalse开启
- [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
- _arrowImage.hidden = NO;
- _arrowImage.transform = CATransform3DIdentity;
- [CATransaction commit];
- // 更新下时间
- [self refreshLastUpdatedDate];
- break;
- /*触摸手指松开,完成下拉操作的状态*/
- case EGOOPullRefreshLoading:
- // _statusLabel.text = NSLocalizedString(@"Loading...", @"Loading Status");
- _statusLabel.text = @"加载中";
- [_activityView startAnimating];
- [CATransaction begin];
- [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
- _arrowImage.hidden = YES;
- [CATransaction commit];
- break;
- default:
- break;
- }
- _state = aState;
- }
[cpp] view plaincopy
- #pragma mark -
- #pragma mark ScrollView Methods
- - (void)egoRefreshScrollViewDidScroll:(UIScrollView *)scrollView {
- if (_state == EGOOPullRefreshLoading) {
- CGFloat offset = MAX(scrollView.contentOffset.y * -1, 0);
- offset = MIN(offset, 60);
- scrollView.contentInset = UIEdgeInsetsMake(offset, 0.0f, 0.0f, 0.0f);
- } else if (scrollView.isDragging) {
- BOOL _loading = NO;
- if ([_delegate respondsToSelector:@selector(egoRefreshTableHeaderDataSourceIsLoading:)]) {
- _loading = [_delegate egoRefreshTableHeaderDataSourceIsLoading:self];
- }
- if (_state == EGOOPullRefreshPulling && scrollView.contentOffset.y > -65.0f && scrollView.contentOffset.y < 0.0f && !_loading) {
- [self setState:EGOOPullRefreshNormal];
- } else if (_state == EGOOPullRefreshNormal && scrollView.contentOffset.y < -65.0f && !_loading) {
- [self setState:EGOOPullRefreshPulling];
- }
- // 设置下拉属性scrollView框架恢复初始位置
- if (scrollView.contentInset.top != 0) {
- // A UIEdgeInsets struct whose top, left, bottom, and right fields are all set to the value 0.
- scrollView.contentInset = UIEdgeInsetsZero;
- }
- }
- }
- - (void)egoRefreshScrollViewDidEndDragging:(UIScrollView *)scrollView {
- BOOL _loading = NO;
- if ([_delegate respondsToSelector:@selector(egoRefreshTableHeaderDataSourceIsLoading:)]) {
- _loading = [_delegate egoRefreshTableHeaderDataSourceIsLoading:self];
- }
- if (scrollView.contentOffset.y <= - 65.0f && !_loading) {
- if ([_delegate respondsToSelector:@selector(egoRefreshTableHeaderDidTriggerRefresh:)]) {
- [_delegate egoRefreshTableHeaderDidTriggerRefresh:self];
- }
- [self setState:EGOOPullRefreshLoading];
- [UIView beginAnimations:nil context:NULL];
- [UIView setAnimationDuration:0.2];
- scrollView.contentInset = UIEdgeInsetsMake(60.0f, 0.0f, 0.0f, 0.0f);
- [UIView commitAnimations];
- }
- }
- //数据加载完成后调用此方法
- - (void)egoRefreshScrollViewDataSourceDidFinishedLoading:(UIScrollView *)scrollView {
- [UIView beginAnimations:nil context:NULL];
- [UIView setAnimationDuration:.3];
- // 数据加载完成后,scrollView恢复位置大小
- [scrollView setContentInset:UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 0.0f)];
- [UIView commitAnimations];
- // 数据加载完成,
- [self setState:EGOOPullRefreshNormal];
- }
[cpp] view plaincopy
- #pragma mark -
- #pragma mark Dealloc
- - (void)dealloc {
- _delegate=nil;
- _activityView = nil;
- _statusLabel = nil;
- _arrowImage = nil;
- _lastUpdatedLabel = nil;
- [super dealloc];
- }
- @end
当我们想使用这个下拉刷新类库的时候,在使用类里声明这个协议<EGORefreshTableHeaderDelegate>,把当前类self交付给下拉刷新库的协议对象,也就是xx.delegate=self;
怎样让其他类来使用这里面效果,这时我们就可以委托另一个类来实现协议的方法。
选中一个协议方法,右键选择Jump to Definition就可以看到哪些类被委托了,怎样使用了这个类的协议方法:
正在学习过程中,错误之处请指正,欢迎交流,共同学习;
欢迎转载分享,请注明出处http://blog.csdn.net/duxinfeng2010
分类: 菜鸟学iOS的笔记
2012-12-18 17:19 3727人阅读 评论(1) 收藏 举报
iOS里委托与协议是很重要的一块,如果理解不好很难区分协议与委托到底有什么不一样,这些东西在开发中是经常遇见的;
协议是类留给外部的一个接口函数的集合(一位高手用C++基类来解释是,把接口做为参数,回调基类的函数时,运行时识别,调用了相应子类的成员函数);
委托是iOS一种设计模式,通过委托别的类,来调用协议里的方法,相当于一个回调过程;
使用理解委托与协议步骤:
(1) 弄清楚谁委托谁,需要干什么?
拿上一篇博客下拉刷新源码案例分析,(在源码工程中comment文件夹里)有MessageSystemView这样一个类,该类用于用户的信息所用(比如谁给你留言,或者评论了你某一篇博客),我们也需要刷新获取最新信息,此处用到下拉刷新第三方类库EGORefreshTableHeaderView类委托MessageSystemView类来实现这个特性,这就需要在EGORefreshTableHeaderView类定义一个协议对象delegate。
(2)被委托类需要在interface中声明<XXDelegate>,表示该类要实现协议里的方法.
MessageSystemView实现EGORefreshTableHeaderView协议方法就要遵循EGORefreshTableHeaderDelegate协议.
(3)在被委托类里定义一个委托类的对象,将xx.delegate=self,意思是把委托的对象只想被委托对象;
在EGORefreshTableHeaderView.h文件中
EGORefreshTableHeaderView*_refreshHeaderView;
在ViewDidLoad中 view.delegate = self; _refreshHeaderView = view;
[cpp] view plaincopy
- - (void)viewDidLoad
- {
- allCount = 0;
- [super viewDidLoad];
- if (self.tabTitle) {
- self.tabBarItem.title = self.tabTitle;
- }
- //加载固定数据
- imageDownloadsInProgress = [NSMutableDictionary dictionary];
- comments = [[NSMutableArray alloc] initWithCapacity:10];
- [self reload:YES];
- //添加的代码
- if (_refreshHeaderView == nil) {
- <span style="color:#ff0000;"> EGORefreshTableHeaderView *view = [[EGORefreshTableHeaderView alloc] initWithFrame:CGRectMake(0.0f, -320.0f, self.view.frame.size.width, 320)];
- view.delegate = self;</span>
- [self.tableComments addSubview:view];
- <span style="color:#ff0000;">_refreshHeaderView = view;</span>
- }
- [_refreshHeaderView refreshLastUpdatedDate];
- self.tableComments.backgroundColor = [UIColor colorWithRed:248.0/255.0 green:249.0/255.0 blue:249.0/255.0 alpha:1.0];
- }
(4)在被委托类的实现文件中调用协议方法,这就是实现委托方法的一个过程;
此处EGORefreshTableHeaderView类对象委托MessageSystemView类对象,在MessageSystemView实现对EGORefreshTableHeaderView类协议的调用;
MessageSystemView.m文件实现委托方法
[cpp] view plaincopy
- - (void)egoRefreshTableHeaderDidTriggerRefresh:(EGORefreshTableHeaderView *)view
- {
- [self reloadTableViewDataSource];
- [self refresh];
- }
- - (BOOL)egoRefreshTableHeaderDataSourceIsLoading:(EGORefreshTableHeaderView *)view
- {
- return _reloading;
- }
- - (NSDate *)egoRefreshTableHeaderDataSourceLastUpdated:(EGORefreshTableHeaderView *)view
- {
- return [NSDate date];
- }
当然要实现完整的下拉功能这几个委托只是其中一部分,被委托类里还需要有自己的成员函数,在委托方法正在被调用的时候触发被委托成员函数方法,在
MessageSystemView.h
[cpp] view plaincopy
- //下拉刷新
- - (void)refresh;//解析网络数据,让数据显示到视图上
- - (void)reloadTableViewDataSource;//开始加载时调用此方法
- - (void)doneLoadingTableViewData;//完成加载时调用此方法
MessageSystemView.m
[cpp] view plaincopy
- #pragma 下提刷新
- - (void)reloadTableViewDataSource
- {
- _reloading = YES;
- }
- - (void)doneLoadingTableViewData
- {
- _reloading = NO;
- [_refreshHeaderView egoRefreshScrollViewDataSourceDidFinishedLoading:self.tableComments];
- }
- - (void)scrollViewDidScroll:(UIScrollView *)scrollView
- {
- [_refreshHeaderView egoRefreshScrollViewDidScroll:scrollView];
- }
- - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
- {
- [_refreshHeaderView egoRefreshScrollViewDidEndDragging:scrollView];
- }
- - (void)egoRefreshTableHeaderDidTriggerRefresh:(EGORefreshTableHeaderView *)view
- {
- [self reloadTableViewDataSource];
- [self refresh];
- }
- - (BOOL)egoRefreshTableHeaderDataSourceIsLoading:(EGORefreshTableHeaderView *)view
- {
- return _reloading;
- }
- - (NSDate *)egoRefreshTableHeaderDataSourceLastUpdated:(EGORefreshTableHeaderView *)view
- {
- return [NSDate date];
- }
- - (void)refresh
- {
- isLoadOver = NO;
- [self reload:NO];
- }
根据这些练习了一个简单的下拉刷新Demo
效果图
.h文件里
[cpp] view plaincopy
- #import <UIKit/UIKit.h>
- #import "EGORefreshTableHeaderView.h"
- @interface ViewController : UIViewController<UIScrollViewDelegate,UITableViewDelegate,UITableViewDataSource, EGORefreshTableHeaderDelegate>
- {
- EGORefreshTableHeaderView *_refreshHeaderView;
- BOOL _reloading;
- }
- @property (retain, nonatomic) IBOutlet UITableView *tableView;
- -(void)reloadTableViewDataSource;
- -(void)doneLoadingTableViewData;
- @end
.m文件里
[cpp] view plaincopy
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- // Do any additional setup after loading the view, typically from a nib.
- if (_refreshHeaderView == nil) {
- EGORefreshTableHeaderView *view = [[EGORefreshTableHeaderView alloc] initWithFrame:CGRectMake(0.0f, -self.tableView.frame.size.height, self.view.frame.size.width, self.tableView.frame.size.height)];
- view.delegate = self;
- [self.tableView addSubview:view];
- _refreshHeaderView = view;
- [view release];
- }
- [_refreshHeaderView refreshLastUpdatedDate];
- }
- //重新加载时调用
- -(void)reloadTableViewDataSource
- {
- _reloading = YES;
- }
- //完成加载时调用
- -(void)doneLoadingTableViewData
- {
- _reloading = NO;
- [_refreshHeaderView egoRefreshScrollViewDataSourceDidFinishedLoading:self.tableView];
- }
- #pragma mark -
- #pragma mark UIScrollViewDelegate Methods
- -(void)scrollViewDidScroll:(UIScrollView *)scrollView
- {
- [_refreshHeaderView egoRefreshScrollViewDidScroll:scrollView];
- }
- -(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
- {
- [_refreshHeaderView egoRefreshScrollViewDidEndDragging:scrollView];
- }
- #pragma mark -
- #pragma mark EGORefreshTableHeaderDelegate Methods
- -(void)egoRefreshTableHeaderDidTriggerRefresh:(EGORefreshTableHeaderView *)view
- {
- [self reloadTableViewDataSource];
- [self performSelector:@selector(doneLoadingTableViewData) withObject:nil afterDelay:3.0];
- }
- -(BOOL)egoRefreshTableHeaderDataSourceIsLoading:(EGORefreshTableHeaderView *)view
- {
- return _reloading;
- }
- -(NSDate *)egoRefreshTableHeaderDataSourceLastUpdated:(EGORefreshTableHeaderView *)view
- {
- return [NSDate date];
- }
- #pragma mark -
- #pragma mark UITableViewDataSource
- -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
- {
- return 1;
- }
- -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
- {
- return 3;
- }
- -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
- {
- static NSString *cellIdentifier = @"cell";
- UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
- if (cell==nil) {
- cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
- }
- cell.textLabel.text = @"下拉刷新测试";
- return cell;
- }
源码:http://download.csdn.net/detail/duxinfeng2010/4902782
开源中国iOS客户端学习——(四)GCDiscreetNotificationView提示视图
分类: 菜鸟学iOS的笔记
2012-12-19 11:38 4168人阅读 评论(11) 收藏 举报
GCDiscreetNotificationView 类库作用是: 在不阻止用户与设备应用程序交互情况下,作为一个通知视图来显示一个当前的状态。
GCDiscreetNotificationView 类库下载地址 https://github.com/gcamp/GCDiscreetNotificationView
在开源中国iOS客户端上,当无法获取网络时,
我们常用的通知可能是一个UIAlertView的警告,提示当前网络未连接,这样就强制用户必须做出选择,被强制的肯定会不爽。这是GCDiscreetNotificationView类库相比较的一个优点;
关于怎样使用GCDiscreetNotificationView第三方类库,在开源中国iOS客户端中,这个开发类库被封装在一个Tool类中(Helper文件夹下),
[cpp] view plaincopy
- + (void)ToastNotification:(NSString *)text andView:(UIView *)view andLoading:(BOOL)isLoading andIsBottom:(BOOL)isBottom
- {
- GCDiscreetNotificationView *notificationView = [[GCDiscreetNotificationView alloc] initWithText:text showActivity:isLoading inPresentationMode:isBottom?GCDiscreetNotificationViewPresentationModeBottom:GCDiscreetNotificationViewPresentationModeTop inView:view];
- [notificationView show:YES];
- [notificationView hideAnimatedAfter:2.6];
- }
然后在MessageSystemView.m的reload方法中调用也就一行代码,当然其他类中也可以调用,只需#import "Tool.h"
[Tool ToastNotification:@"错误网络无连接" andView:self.view andLoading:NO andIsBottom:NO];
GCDiscreetNotificationView类库不仅可以在顶部显示,还可以在底部显示,只需修改andIsBottom:传入的BOOL型参数为YES,这样它就在底部显示了。andLoading接受BOOL型参数用于显示一个加载过程。
我将这个类库放到另一个工程中,仿照开源中国iOS客户端里的方法用Tool类进行封装,做的一个测试
底部显示
从中我们应该能体会到使用第三方类库好处了吧,我们不需要研究它是如何实现,知道有这个特效,然后只需调用接口就可;
正在学习过程中,错误之处请指正,欢迎交流,共同学习;
欢迎转载分享,请注明出处http://blog.csdn.net/duxinfeng2010
Baidu Button BEGIN
分类: 菜鸟学iOS的笔记
2012-12-31 18:32 3629人阅读 评论(0) 收藏 举报
目录(?)
[+]
如今的应用大部分基予网络,在开源中国iOS客户端源码中关于网络通信方面用了三个类库,ASI和AFNetworking,还有一个苹果官方给出的Reachability用于检测当前网络状况,本文介绍当前用的比较多的ASI类库;
ASIHTTPRequest简称ASI,它是对CFNetwork API进行封装,使在与web服务器通信时的繁琐步骤变得容易一些。它是使用Objective-C 编写,能够很好的用在Mac OS X和iPhone应用程序中;它适用于执行基本的HTTP请求和交互基于 REST的服务(GET / POST / PUT /DELETE)互交。
ASIHTTPRequest下载 https://github.com/pokeb/asi-http-request/tree
关于ASI类库介绍在 http://allseeing-i.com/ASIHTTPRequest/
添加ASI到你工程中步骤 http://allseeing-i.com/ASIHTTPRequest/Setup-instructions
ASI特点
l通过简单的接口,即可完成向服务端提交数据和从服务端获取数据的工作
l下载的数据,可存储到内存中或直接存储到磁盘中
l能上传本地文件到服务端
l可以方便的访问和操作请求和返回的Http头信息
l可以获取到上传或下载的进度信息,为应用程序提供更好的体验
l支持上传或下载队列,并且可获取队列的进度信息
l支持基本、摘要和NTLM身份认证,在同一会话中授权凭证会自动维持,并且可以存储在Keychain(Mac和iOS操作 系统的密码管理系统)中
l 支持Cookie
l当应用(iOS4+)在后台运行时,请求可以继续运行
l 支持GZIP压缩数据
l内置的ASIDownloadCache类,可以缓存请求返回的数据,这样即使没有网络也可以返回已经缓存的数据结果
l ASIWebPageRequest –可以下载完整的网页,包括包含的网页、样式表、脚本等资源文件,并显示在UIWebView /WebView中。任意大小的页面都可以无限期缓存,这样即使没有网络也可以离线浏览
l支持客户端证书
l支持通过代理发起Http请求
l支持带宽限制。在iOS平台,可以根据当前网络情况来自动决定是否限制带宽,例如当使 用WWAN(GPRS/Edge/3G)网络时限制,而当使用WIFI时不做任何限制
l支持断点续传
l支持同步和异步请
ASI类库里包括22个文件,4个主要的类ASIHTTPRequest 、ASIFormDataRequest、ASINetworkQueue、ASIDownloadCache,5个支持的类ASIInputStream、ASIDataDecompressor、ASIDataCompressor、ASIAuthenticationDialog、Reachability,4个协议配置文件ASIHTTPRequestDelegate、ASIProgressDelegate、ASICacheDelegate、ASIHTTPRequestConfig.h,这些文件作用在开发文档中都有详细介绍.
在http://allseeing-i.com/ASIHTTPRequest/How-to-use有关于初次接触ASI的简单使用,很有必要看一看,
了解简单的同步请求、异步请求,block块请求,队列请求等其他用法。
用ASI写的一个简单请求数据的Demo:
测试使用的URL是国家气象局API,返回一个json数据
#define URL @"http://www.weather.com.cn/data/sk/101010100.html"
请求得到数据:
[cpp] view plaincopy
- //同步请求
- - (IBAction)synchronization_bt:(id)sender {
- NSURL *url = [NSURL URLWithString:URL];
- ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
- // 启动同步方式访问
- [request startSynchronous];
- NSError *error = [request error];
- // 请求成功
- if (!error) {
- NSString *response = [request responseString];
- NSLog(@"请求数据:%@",response);
- }
- }
- }
[cpp] view plaincopy
- //异步请求
- - (IBAction)asynchronous_bt:(id)sender {
- NSURL *url = [NSURL URLWithString:URL];
- ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
- [request setDelegate:self];
- // 启动异步方式访问
- [request startAsynchronous];
- }
- //异步请求Delegate Methods
- -(void)requestFinished:(ASIHTTPRequest *)request
- {
- NSString *responseString = [request responseString];
- NSLog(@"请求的String数据:%@",responseString);
- // 以 二进制文件形式存储
- NSData *responseData = [request responseData];
- NSLog(@"请求的Data数据:%@",responseData);
- }
- -(void)requestFailed:(ASIHTTPRequest *)request
- {
- NSError *error = [request error];
- NSLog(@"Error:%@",error.userInfo);
- }
[cpp] view plaincopy
- //block块请求
- - (IBAction)blocks_tn:(id)sender {
- NSURL *url = [NSURL URLWithString:URL];
- __block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
- [request setCompletionBlock:^{
- NSString *responseString = [request responseString];
- NSLog(@"请求的String数据:%@",responseString);
- }];
- [request setFailedBlock:^{
- NSError *error = [request error];
- NSLog(@"Error:%@",error.userInfo);
- }];
- [request startAsynchronous];
- }
[cpp] view plaincopy
- //队列请求
- - (IBAction)queue_bt:(id)sender {
- if (![self queue]) {
- [self setQueue:[[[NSOperationQueue alloc]init]autorelease]];
- }
- NSURL *url = [NSURL URLWithString:URL];
- ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
- [request setDelegate:self];
- [request setDidFinishSelector:@selector(requestDone:)];
- [request setDidFailSelector:@selector(requestWentWrong:)];
- [[self queue] addOperation:request];
- }
- -(void)requestDone:(ASIHTTPRequest *)request
- {
- NSString *response = [request responseString];
- NSLog(@"请求的数据:%@",response);
- }
- -(void)requestWentWrong:(ASIHTTPRequest *)request
- {
- NSError *error = [request error];
- NSLog(@"Error:%@",error.userInfo);
- }
将类库加入到工程中不要忘了添加支持的framework框架和库:
SystemConfiguration.framework, MobileCoreServices.framework, CoreGraphics.framework 和 libz.dylib.
源代码:http://download.csdn.net/detail/duxinfeng2010/4947729
ASIHTTPRequest中文文档:
http://www.dreamingwish.com/dream-2011/apples-third-party-development-libraries-asihttprequest.html
正在学习过程中,错误之处请指正,欢迎交流,共同学习;
欢迎转载分享,请注明出处http://blog.csdn.net/duxinfeng2010
Baidu Button BEGIN
Baidu Button END 192.168.100.35
- 上一篇
下一篇
Baidu Button BEGIN Baidu Button END分类: 菜鸟学iOS的笔记
2013-01-03 10:06 10349人阅读 评论(15) 收藏 举报
开源中国iOS客户端基于网络同步数据,从而达到与网页看到同样数据效果,所以在启动程序的时候需要检查网络;这也是每一个联网应用启动的第一步,如果联网应用没有检查网络,苹果公司将不予以审核通过;
开源中国iOS客户端大牛们在写网络检测时很迷惑人,开始以为他们用的是ASI类库做的网络检测,今天才看明白,他们并不是用的ASI类库检测,而是用到AFNetworking这个类库里一个实例方法做网络连接检测;
先看Appdelegate文件:
在application:didFinishLaunchingWithOptions:方法里
[cpp] view plaincopy
- //检查网络是否存在 如果不存在 则弹出提示
- [Config Instance].isNetworkRunning = [CheckNetwork isExistenceNetwork];
在applicationDidBecomeActive:方法里
[cpp] view plaincopy
- - (void)applicationDidBecomeActive:(UIApplication *)application
- {
- [Config Instance].isNetworkRunning = [CheckNetwork isExistenceNetwork];
- if ([Config Instance].isNetworkRunning == NO) {
- UIAlertView *myalert = [[UIAlertView alloc] initWithTitle:@"警告" message:@"未连接网络,将使用离线模式" delegate:self cancelButtonTitle:@"确认" otherButtonTitles:nil,nil];
- [myalert show];
- }
- }
都用到了[Config Instance].isNetworkRunning = [CheckNetwork isExistenceNetwork];再看看Config和CheckNetwork这两个类定义
Config类的Instance方法,
[cpp] view plaincopy
- static Config * instance = nil;
- +(Config *) Instance
- {
- @synchronized(self)
- {
- if(nil == instance)
- {
- [self new];
- }
- }
- return instance;
- }
从字面意思也能推测出是给Cinfig类实例化用的,isNetworkRunning是BOOL型变量
CheckNetwork在ASIHttp文件里,和ASI类库放到一块的,(里面汉字出现乱码)
[cpp] view plaincopy
- +(BOOL)isExistenceNetwork
- {
- // BOOL isExistenceNetwork;
- // Reachability *r = [Reachability reachabilityWithHostName:@"www.oschina.net"];
- // switch ([r currentReachabilityStatus]) {
- // case NotReachable:
- // isExistenceNetwork=FALSE;
- // // NSLog(@"娌℃湁缃戠粶");
- // break;
- // case ReachableViaWWAN:
- // isExistenceNetwork=TRUE;
- // // NSLog(@"姝e湪浣跨敤3G缃戠粶");
- // break;
- // case ReachableViaWiFi:
- // isExistenceNetwork=TRUE;
- // // NSLog(@"姝e湪浣跨敤wifi缃戠粶");
- // break;
- // }
- // return isExistenceNetwork;
- return YES;
- }
本来是使用苹果官方提供的Reachability来检测网络连接状况,但是大牛们又给注释掉了,return YES;
也就是[Config Instance].isNetworkRunning=YES;
但是当我把iMac网线拔掉运行的时候却能检测出网络无连接,通过查找 “错误 网络无连接”
发现他们都在AFNetworking类库
- (void)postPath:(NSString *)path parameters:(NSDictionary *)parameters success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure 方法里面,
这个方法使用AFHTTPRequestOperation和“PATCH”请求HTTP客户端操作队列,使用到了block块(iOS 4.0+特性),URL请求成功执行success块里操作,这里面block块没有返回值,接受两个参数,创建请求操作和响应数据请求,URL请求失败执行failure里面的方法,这个block块里仍没有返回值,接受两个参数创建请求操作和NSError对象,描述网络或解析错误状况;
所以才有了上面截图中网络的连接检测,拿源码中一处来举例
正在学习过程中,错误之处请指正,欢迎交流,共同学习;
欢迎转载分享,请注明出处http://blog.csdn.net/duxinfeng2010
Baidu Button BEGIN
Baidu Button END 192.168.100.35
- 上一篇
下一篇
Baidu Button BEGIN Baidu Button ENDBaidu Button END 192.168.100.35
开源中国iOS客户端学习——(七)MBProgressHUD特效
分类: 菜鸟学iOS的笔记
2013-01-16 13:55 13431人阅读 评论(11) 收藏 举报
在开源中国iOS客户端中也用到了MBProgressHUD这个特效,主要作用为应用显示一个过渡的作用,常用于打开一个联网页面加载过程,防止出现假死现象,如果网速慢则告诉用户已经在很努力很努力的加载中。
GitHub上下载地址:https://github.com/jdg/MBProgressHUD
源码中也自带了一个Demo,显示13中动画效果,可以根据需要选取其中特效加以使用,使用方法基本一样;使用的时候只加把MBProgressHUD.h和MBProgressHUD.m拖入工程中,在使用的文件中加上#import"MBProgressHUD.h"
在开源中国iOS客户端中只用到一种特效,当我们选取一条资讯查看详细信息时:
我们在跳转到实现的代码部分,在NewsDetail.m的clickFavorite和viewDidLoad方法中
[cpp] view plaincopy
- - (void)clickFavorite:(id)sender
- {
- UIBarButtonItem * btn = (UIBarButtonItem *)sender;
- BOOL isFav = [btn.title isEqualToString:@"收藏此文"];
- MBProgressHUD *hud = [[MBProgressHUD alloc] initWithView:self.view];
- [Tool showHUD:isFav ? @"正在添加收藏":@"正在删除收藏" andView:self.view andHUD:hud];
- [[AFOSCClient sharedClient]getPath:isFav ? api_favorite_add : api_favorite_delete
- parameters:[NSDictionary dictionaryWithObjectsAndKeys:
- [NSString stringWithFormat:@"%d", [Config Instance].getUID],@"uid",
- [NSString stringWithFormat:@"%d", newsID],@"objid",
- @"4",@"type", nil] success:^(AFHTTPRequestOperation *operation, id responseObject) {
- [hud hide:YES];
- [Tool getOSCNotice2:operation.responseString];
- ApiError *error = [Tool getApiError2:operation.responseString];
- if (error == nil) {
- [Tool ToastNotification:operation.responseString andView:self.view andLoading:NO andIsBottom:NO];
- return ;
- }
- switch (error.errorCode)
- {
- case 1:
- {
- btnFavorite.title = isFav ? @"取消收藏" : @"收藏此文";
- self.singleNews.favorite = !self.singleNews.favorite;
- }
- break;
- case 0:
- case -2:
- case -1:
- {
- [Tool ToastNotification:[NSString stringWithFormat:@"错误 %@",error.errorMessage] andView:self.view andLoading:NO andIsBottom:NO];
- }
- break;
- }
- } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
- [hud hide:YES];
- [Tool ToastNotification:@"添加收藏失败" andView:self.view andLoading:NO andIsBottom:NO];
- }];
- }
[cpp] view plaincopy
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- self.tabBarItem.title = @"资讯详情";
- self.tabBarItem.image = [UIImage imageNamed:@"detail"];
- //WebView的背景颜色去除
- [Tool clearWebViewBackground:self.webView];
- self.singleNews = [[SingleNews alloc] init];
- self.navigationController.title = @"资讯详情";
- self.webView.delegate = self;
- [self.webView loadHTMLString:@"" baseURL:nil];
- if ([Config Instance].isNetworkRunning)
- {
- MBProgressHUD *hud = [[MBProgressHUD alloc] initWithView:self.view];
- [Tool showHUD:@"正在加载" andView:self.view andHUD:hud];
- NSString *url = [NSString stringWithFormat:@"%@?id=%d",api_news_detail, newsID];
- [[AFOSCClient sharedClient] getPath:url parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
- [Tool getOSCNotice2:operation.responseString];
- [hud hide:YES];
- self.singleNews = [Tool readStrNewsDetail:operation.responseString];
- if (self.singleNews == nil) {
- [Tool ToastNotification:@"加载失败" andView:self.view andLoading:NO andIsBottom:NO];
- return;
- }
- [self loadData:self.singleNews];
- //如果有网络 则缓存它
- if ([Config Instance].isNetworkRunning)
- {
- [Tool saveCache:1 andID:self.singleNews._id andString:operation.responseString];
- }
- } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
- [hud hide:YES];
- if ([Config Instance].isNetworkRunning) {
- [Tool ToastNotification:@"错误 网络无连接" andView:self.view andLoading:NO andIsBottom:NO];
- }
- }];
- }
- else
- {
- NSString *value = [Tool getCache:1 andID:newsID];
- if (value) {
- self.singleNews = [Tool readStrNewsDetail:value];
- [self loadData:self.singleNews];
- }
- else {
- [Tool ToastNotification:@"错误 网络无连接" andView:self.view andLoading:NO andIsBottom:NO];
- }
- }
- }
分析viewDidLoad方法,
首先是判断网络是否连通状态,如果是
定义在当前的view中定义一个MBProgressHUD对象,进行初始化
[ToolshowHUD:@"正在加载" andView:self.viewandHUD:hud];是在Tool类里面进行的一次封装,设置MBProgressHUD的显示信息
[cpp] view plaincopy
- + (void)showHUD:(NSString *)text andView:(UIView *)view andHUD:(MBProgressHUD *)hud
- {
- [view addSubview:hud];
- hud.labelText = text;//显示提示
- hud.dimBackground = YES;//使背景成黑灰色,让MBProgressHUD成高亮显示
- hud.square = YES;//设置显示框的高度和宽度一样
- [hud show:YES];
- }
然后在用到AFNetWork类库的getPath:parameters:success:failure:方法,嵌套在block块中判断请求的url是否成功,在执行[Tool getOSCNotice2:operation.responseString];这个方法也是封装在Tool类中,封装的是TBXML解析器,如果解析成功立即设置MBProgressHUD隐藏属性[hud hide:YES];如果请求的url不成功直接设置MBProgressHUD隐藏属性[hud hide:YES],再用GCDiscreetNotificationView进行通知“错误 网络无连接”;
开源中国iOS客户端学习——(八)网络通信AFNetworking类库
分类: 菜鸟学iOS的笔记
2013-02-28 21:55 21535人阅读 评论(5) 收藏 举报
AFNetworking是一个轻量级的iOS网络通信类库,继ASI类库不在更新之后开发者们有一套不错选择;
AFNetworking类库源码下载和使用教程: https://github.com/AFNetworking/AFNetworking
如果想深入研究有官方文档介绍:http://afnetworking.github.com/AFNetworking/
在开源中国iOS客户端中关于AFNetworking类库的使用只用到了两个实例方法
(1)getPath:parameters:success:failure:
(2)postPath:parameters:success:failure:
他们用法基本相同,只是请求数据方式不同,一种是Get请求和Post请求。Get是向服务器发索取数据的一种请求,也就相当于查询信息功能,不会修改类容,Post是向服务器提交数据的一种请求,影响数据内容;两种方法定义:
[cpp] view plaincopy
- - (void)getPath:(NSString *)path
- parameters:(NSDictionary *)parameters
- success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
- failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
- {
- NSURLRequest *request = [self requestWithMethod:@"GET" path:path parameters:parameters];
- AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure];
- [self enqueueHTTPRequestOperation:operation];
- }
[cpp] view plaincopy
- - (void)postPath:(NSString *)path
- parameters:(NSDictionary *)parameters
- success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
- failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
- {
- NSURLRequest *request = [self requestWithMethod:@"POST" path:path parameters:parameters];
- AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure];
- [self enqueueHTTPRequestOperation:operation];
- }
getPath:parameters:success:failure:方法在程序中使用举例:
NewsView.m
[cpp] view plaincopy
- - (void)reload:(BOOL)noRefresh
- {
- //如果有网络连接
- if ([Config Instance].isNetworkRunning) {
- if (isLoading || isLoadOver) {
- return;
- }
- if (!noRefresh) {
- allCount = 0;
- }
- int pageIndex = allCount/20;
- NSString *url;
- switch (self.catalog) {
- case 1:
- url = [NSString stringWithFormat:@"%@?catalog=%d&pageIndex=%d&pageSize=%d", api_news_list, 1, pageIndex, 20];
- break;
- case 2:
- url = [NSString stringWithFormat:@"%@?type=latest&pageIndex=%d&pageSize=%d", api_blog_list, pageIndex, 20];
- break;
- case 3:
- url = [NSString stringWithFormat:@"%@?type=recommend&pageIndex=%d&pageSize=%d", api_blog_list, pageIndex, 20];
- break;
- }
- [[AFOSCClient sharedClient]getPath:url parameters:Nil
- success:^(AFHTTPRequestOperation *operation, id responseObject) {
- [Tool getOSCNotice2:operation.responseString];
- isLoading = NO;
- if (!noRefresh) {
- [self clear];
- }
- @try {
- NSMutableArray *newNews = self.catalog <= 1 ?
- [Tool readStrNewsArray:operation.responseString andOld: news]:
- [Tool readStrUserBlogsArray:operation.responseString andOld: news];
- int count = [Tool isListOver2:operation.responseString];
- allCount += count;
- if (count < 20)
- {
- isLoadOver = YES;
- }
- [news addObjectsFromArray:newNews];
- [self.tableNews reloadData];
- [self doneLoadingTableViewData];
- //如果是第一页 则缓存下来
- if (news.count <= 20) {
- [Tool saveCache:5 andID:self.catalog andString:operation.responseString];
- }
- }
- @catch (NSException *exception) {
- [NdUncaughtExceptionHandler TakeException:exception];
- }
- @finally {
- [self doneLoadingTableViewData];
- }
- } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
- NSLog(@"新闻列表获取出错");
- //如果是刷新
- [self doneLoadingTableViewData];
- if ([Config Instance].isNetworkRunning == NO) {
- return;
- }
- isLoading = NO;
- if ([Config Instance].isNetworkRunning) {
- [Tool ToastNotification:@"错误 网络无连接" andView:self.view andLoading:NO andIsBottom:NO];
- }
- }];
- isLoading = YES;
- [self.tableNews reloadData];
- }
- //如果没有网络连接
- else
- {
- NSString *value = [Tool getCache:5 andID:self.catalog];
- if (value) {
- NSMutableArray *newNews = [Tool readStrNewsArray:value andOld:news];
- [self.tableNews reloadData];
- isLoadOver = YES;
- [news addObjectsFromArray:newNews];
- [self.tableNews reloadData];
- [self doneLoadingTableViewData];
- }
- }
- }
分析一下这里面的代码:
首先是做一个网络连接判断,在开源中国iOS客户端学习——(六)网络连接检测一文中介绍了,作者并不是用这种方法来判断,而是使用getPath:parameters:success:failure:来判断网络的连接,方法使用AFHTTPRequestOperation和“PATCH”请求HTTP客户端操作队列,使用到了block块(iOS 4.0+特性),URL请求成功执行success块里操作,这里面block块没有返回值,接受两个参数,创建请求操作和响应数据请求,URL请求失败执行failure里面的方法,这个block块里仍没有返回值,接受两个参数创建请求操作和NSError对象,描述网络或解析错误状况;
在 if()中的方法[Config Instance].isNetworkRunning==YES的,如果程序加载或者已经加载完毕什么也不返回,如果程序没有加载数据,将数据列表数量显示为0,接下来是在switch()中,根据使用者选择设置不同API接口(下图),然后就是解析显示数据信息,显示在视图中;
在AFNetwork 文件夹中,作者自己添加了一个AFOSCClient类,该类继承AFHTTPClient,又设计了一个sharedClient的类方法,从返回的结果可以推测出它是通过API请求返回json类型的数据,具体什么作用还没看出来;
[Tool getOSCNotice2:operation.responseString];是封装在在Tool类中的解析获取的XML的文件
URL请求成功,还做了一个程序异常处理,防止请求数据过成功程序异常崩溃
关于@try @catch @finally异常处理的使用:
@try
{
//执行的代码,其中可能有异常。一旦发现异常,则立即跳到catch执行。否则不会执行catch里面的内容
}
@catch
{
//除非try里面执行代码发生了异常,否则这里的代码不会执行
}
@finally
{
//不管什么情况都会执行,包括try catch 里面用了return ,可以理解为只要执行了try或者catch,就一定会执行 finally
}
如果URL请求的数据出错,则反应网络不连通,数据不能加载,则弹出GCDiscreetNotificationView提示视图 提示网络错误;
postPath:parameters:success:failure:方法在程序中使用举例:
FriendsView.m
[cpp] view plaincopy
- -(void)reload:(BOOL)noRefresh
- {
- if (isLoadOver) {
- [self doneLoadingTableViewData];
- return;
- }
- [[AFOSCClient sharedClient] postPath:api_friends_list
- parameters:[NSDictionary dictionaryWithObjectsAndKeys:segement.selectedSegmentIndex == 0 ? @"1" : @"0",@"relation",
- [NSString stringWithFormat:@"%d", friends.count/20],@"pageIndex",
- @"20",@"pageSize",
- [NSString stringWithFormat:@"%d", [Config Instance].getUID],@"uid",nil] success:^(AFHTTPRequestOperation *operation, id responseObject) {
- if (!noRefresh) {
- [self clear];
- }
- [self doneLoadingTableViewData];
- isLoading = NO;
- NSString *response = operation.responseString;
- [Tool getOSCNotice2:response];
- @try {
- TBXML *xml = [[TBXML alloc] initWithXMLString:response error:nil];
- TBXMLElement *root = xml.rootXMLElement;
- //显示
- TBXMLElement *_friends = [TBXML childElementNamed:@"friends" parentElement:root];
- if (!_friends) {
- isLoadOver = YES;
- [self.tableFriends reloadData];
- return;
- }
- TBXMLElement *first = [TBXML childElementNamed:@"friend" parentElement:_friends];
- if (first == nil) {
- [self.tableFriends reloadData];
- isLoadOver = YES;
- return;
- }
- NSMutableArray *newFriends = [[NSMutableArray alloc] initWithCapacity:20];
- TBXMLElement *name = [TBXML childElementNamed:@"name" parentElement:first];
- TBXMLElement *userid = [TBXML childElementNamed:@"userid" parentElement:first];
- TBXMLElement *portrait = [TBXML childElementNamed:@"portrait" parentElement:first];
- TBXMLElement *expertise = [TBXML childElementNamed:@"expertise" parentElement:first];
- TBXMLElement *gender = [TBXML childElementNamed:@"gender" parentElement:first];
- Friend *f = [[Friend alloc] initWithParameters:[TBXML textForElement:name] andUID:[[TBXML textForElement:userid] intValue] andPortrait:[TBXML textForElement:portrait] andExpertise:[TBXML textForElement:expertise] andMale:[[TBXML textForElement:gender] intValue] == 1];
- if (![Tool isRepeatFriend: friends andFriend:f]) {
- [newFriends addObject:f];
- }
- while (first) {
- first = [TBXML nextSiblingNamed:@"friend" searchFromElement:first];
- if (first) {
- name = [TBXML childElementNamed:@"name" parentElement:first];
- userid = [TBXML childElementNamed:@"userid" parentElement:first];
- portrait = [TBXML childElementNamed:@"portrait" parentElement:first];
- expertise = [TBXML childElementNamed:@"expertise" parentElement:first];
- gender = [TBXML childElementNamed:@"gender" parentElement:first];
- f = [[Friend alloc] initWithParameters:[TBXML textForElement:name] andUID:[[TBXML textForElement:userid] intValue] andPortrait:[TBXML textForElement:portrait] andExpertise:[TBXML textForElement:expertise] andMale:[[TBXML textForElement:gender] intValue] == 1];
- if (![Tool isRepeatFriend:friends andFriend:f]) {
- [newFriends addObject:f];
- }
- }
- else
- break;
- }
- if (newFriends.count < 20) {
- isLoadOver = YES;
- }
- [friends addObjectsFromArray:newFriends];
- [self.tableFriends reloadData];
- }
- @catch (NSException *exception) {
- [NdUncaughtExceptionHandler TakeException:exception];
- }
- @finally {
- [self doneLoadingTableViewData];
- }
- } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
- NSLog(@"好友列表获取出错");
- [self doneLoadingTableViewData];
- isLoading = NO;
- if ([Config Instance].isNetworkRunning) {
- [Tool ToastNotification:@"错误 网络无连接" andView:self.view andLoading:NO andIsBottom:NO];
- }
- }];
- isLoading = YES;
- [self.tableFriends reloadData];
- }
这个方法和getPath:parameters:success:failure:不同的在于请求方式是POST请求,可以向服务器里提交数据;
Baidu Button BEGIN
分类: 菜鸟学iOS的笔记
2013-03-09 15:17 2086人阅读 评论(5) 收藏 举报
开源中国客户端中无论是综合里面文章,还是问答里问题还是动弹离得说说,每一条后面都会注释有时间,比如“10分钟之前” “2小时前” “5天前” 或者直接是时间显示“2013-2-9”等,这些时间在很多应用里都是必须的,为的是给用户一个时间感,知道信息是最新的,也方便根据时间查阅以往信息;
这些时间从API解析下来的时间格式都为 yyyy-MM-dd HH:mm:ss(比如:2013-03-09 09:51:22),通过在API上获取文章时间后经过算法转换而得到,在客户端源码的Tool.m中+ (NSString *)intervalSinceNow: (NSString *) theDate 实现这一个方法: 如果信息发表在1小时之前显示分钟,一天之内的信息显示小时,10天之内按天显示,10天之外安所发表时间进行显示:
[cpp] view plaincopy
- + (NSString *)intervalSinceNow: (NSString *) theDate
- {
- NSDateFormatter *date=[[NSDateFormatter alloc] init];
- [date setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
- NSDate *d=[date dateFromString:theDate];
- NSTimeInterval late=[d timeIntervalSince1970]*1;
- NSDate* dat = [NSDate dateWithTimeIntervalSinceNow:0];
- NSTimeInterval now=[dat timeIntervalSince1970]*1;
- NSString *timeString=@"";
- NSTimeInterval cha=now-late;
- // 发表在一小时之内
- if (cha/3600<1) {
- if (cha/60<1) {
- timeString = @"1";
- }
- else
- {
- timeString = [NSString stringWithFormat:@"%f", cha/60];
- timeString = [timeString substringToIndex:timeString.length-7];
- }
- timeString=[NSString stringWithFormat:@"%@分钟前", timeString];
- }
- // 在一小时以上24小以内
- else if (cha/3600>1&&cha/86400<1) {
- timeString = [NSString stringWithFormat:@"%f", cha/3600];
- timeString = [timeString substringToIndex:timeString.length-7];
- timeString=[NSString stringWithFormat:@"%@小时前", timeString];
- }
- // 发表在24以上10天以内
- else if (cha/86400>1&&cha/864000<1)
- {
- timeString = [NSString stringWithFormat:@"%f", cha/86400];
- timeString = [timeString substringToIndex:timeString.length-7];
- timeString=[NSString stringWithFormat:@"%@天前", timeString];
- }
- // 发表时间大于10天
- else
- {
- // timeString = [NSString stringWithFormat:@"%d-%"]
- NSArray *array = [theDate componentsSeparatedByString:@" "];
- // return [array objectAtIndex:0];
- timeString = [array objectAtIndex:0];
- }
- return timeString;
- }
这段代码可以用到自己工程里直接就可以用了,返回的timeString即为需时间段时间;
Demo下载地址:https://github.com/XFZLDXF/MyDemo.git
分类: 菜鸟学iOS的笔记
2013-05-22 11:14 10388人阅读 评论(10) 收藏 举报
数据加密在解密在软件开发过程中举足轻重的作用,可能有的公司在加密的时候有自己公司内部一套设计的算法,而在这方面不想浪费太大精力就可以去考虑使用第三方提供的加密算法,如AES加密算法,本篇内容介绍开源中国iOS客户端使用ASE算法加密密码;
AES GitHub 下载地址 https://github.com/Gurpartap/AESCrypt-ObjC
对一个比较大的工程我们可能都不知道某个类库或者方法在哪被使用,但是智能的Xcode给我们提供了一个全局搜索的功能,我们可以在真个工程中来搜索这个方法。 比如我不知道AES这个类库用在哪了,但是如果使用这个类库肯定会引用它的头文件,我们搜索AESCrypt
然后除了类库本身只有Config类里面包含AESCrpt.h,只有两个方法用到了,跳转到Config.m中的两个方法
[cpp] view plaincopy
- -(void)saveUserNameAndPwd:(NSString *)userName andPwd:(NSString *)pwd
- {
- NSUserDefaults * settings = [NSUserDefaults standardUserDefaults];
- [settings removeObjectForKey:@"UserName"];
- [settings removeObjectForKey:@"Password"];
- [settings setObject:userName forKey:@"UserName"];
- pwd = [AESCrypt encrypt:pwd password:@"pwd"];
- [settings setObject:pwd forKey:@"Password"];
- [settings synchronize];
- }
[cpp] view plaincopy
- -(NSString *)getPwd
- {
- NSUserDefaults * settings = [NSUserDefaults standardUserDefaults];
- NSString * temp = [settings objectForKey:@"Password"];
- return [AESCrypt decrypt:temp password:@"pwd"];
- }
从上面两个方法的方法名知道方法作用,一个是保存用户名和密码,密码使用了AES加密,另一个是解密密码后再返回这个密码;保存用户名和密码是将用户名和密码放到了本地的一个沙盒只之中,获取的时候直接从本地读取加密后的文件,经过解密和服务器上用户数据进行比较(想了解开源中国iOS客户端用户登陆处理过程,敬请关注下一篇博客 《开源中国iOS客户端学习——(十二)用户登陆》,即将推出);
正如官方给出示例用法一样,AES的使用非常简单,首先要添加头文件 #import "AESCrypt.h",使用示例
[cpp] view plaincopy
- NSString *pwdKey = @"新风作浪";
- NSString *password = @"duxinfeng123456";
- NSString *encryptedPWD = [AESCrypt encrypt:password password:pwdKey];
- NSString *decryptedPWD = [AESCrypt decrypt:encryptedPWD password:pwdKey];
- NSLog(@"加密后密码:%@ 解密后密码: %@",encryptedPWD,decryptedPWD);
打印结果 : 加密后密码:/OtTRA5Qz5+xjHB809APLA== 解密后密码: duxinfeng123456
加密 解密方法函数原型,传入的两个参数第一个是加密的数据,第二个是加密数据的key,解密的时候也需要这个key来解密加密后的数据;
[cpp] view plaincopy
- + (NSString *)encrypt:(NSString *)message password:(NSString *)password;
- + (NSString *)decrypt:(NSString *)base64EncodedString password:(NSString *)password;
原创博客欢迎转载分享,请注明出处http://blog.csdn.net/duxinfeng2010
Baidu Button BEGIN
Baidu Button END 192.168.100.35
分类: 菜鸟学iOS的笔记
2013-05-21 12:17 5479人阅读 评论(5) 收藏 举报
开源中国社区团队基于开源项目 GitLab 开发了一款和GitHub一样的在线代码托管平台 Git @ OSC。并且开源客户端的源码在GitHub上不做更新,迁移到Git @OSC上了,欲了解更多请访问Git @ OSC官网http://git.oschina.net
客户端最新源码下载地址:http://git.oschina.net/oschina/iphone-app
回归正题,今天分析的是开源中国iOS客户端搜索功能涉及道一些知识,XML解析和动态加载表视图单元格;
在软件首页右上角有一个搜索按钮,点击进入搜索界面,当搜索的内容很多时我们下拉点击 “下面20项。。。”可以在加载20项,这些数据如何填充到表视图之中?
负责搜索功能的是search下的searchView类,xib控件已经已经做好布局,首先说下SearchView.h文件属性成员代表的作用;
[cpp] view plaincopy
- #import <UIKit/UIKit.h>
- #import "SearchResult.h"
- #import "MBProgressHUD.h"
- @interface SearchView : UIViewController<UITableViewDelegate,UITableViewDataSource,UISearchBarDelegate>
- {
- // 可变数组存放解析的数据
- NSMutableArray * results;
- // 搜索的时候判断是否正在加载数据
- BOOL isLoading;
- // 判断数据是否加载完毕
- BOOL isLoadOver;
- // 记录表视图单元格应该加载数据总条数
- int allCount;
- }
- @property (strong, nonatomic) IBOutlet UISegmentedControl *segmentSearch;
- @property (strong, nonatomic) IBOutlet UITableView *tableResult;
- @property (strong, nonatomic) IBOutlet UISearchBar *_searchBar;
- //根据搜索关键字在不同分类中进行搜索
- - (IBAction)segementChanged:(id)sender;
- //搜索
- -(void)doSearch;
- //清空上次搜索记录
- -(void)clear;
OK现在挺进SearchView.m文件,如果搜索的内容不为空开始 dosearch方法,dosearch方法中使用了ASNetwork类库封装的post网络请求方法(关于AFNetwork post get请求方法请看http://blog.csdn.net/duxinfeng2010/article/details/8620901)
[cpp] view plaincopy
- - (void)postPath:(NSString *)path
- parameters:(NSDictionary *)parameters
- success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
- failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
post请求无法获取它的url,但是可以取出请求成功返回来的数据,比如搜索iOS 返回的xml
[html] view plaincopy
- <?xml version="1.0" encoding="UTF-8"?>
- <oschina>
- <pagesize>20</pagesize>
- <results>
- <result>
- <objid>18397</objid>
- <type>software</type>
- <title><![CDATA[iOS应用开发模板 iOS Boilerplate]]></title>
- <url><![CDATA[http://www.oschina.net/p/ios-boilerplate]]></url>
- <pubDate></pubDate>
- <author></author>
- </result>
- <result>
- <objid>18977</objid>
- <type>software</type>
- <title><![CDATA[ ios-static-libraries]]></title>
- <url><![CDATA[http://www.oschina.net/p/ios-static-libraries]]></url>
- <pubDate></pubDate>
- <author></author>
- </result>
- <result>
- <objid>23309</objid>
- <type>software</type>
- <title><![CDATA[ 仿陌陌的ios客户端]]></title>
- <url><![CDATA[http://www.oschina.net/p/momo-ios-app]]></url>
- <pubDate></pubDate>
- <author></author>
- </result>
- <result>
- <objid>22121</objid>
- <type>software</type>
- <title><![CDATA[iOS任务管理器 cheddar-ios]]></title>
- <url><![CDATA[http://www.oschina.net/p/cheddar-ios]]></url>
- <pubDate></pubDate>
- <author></author>
- </result>
- <result>
- <objid>22900</objid>
- <type>software</type>
- <title><![CDATA[白宫网站 iOS 客户端 wh-app-ios]]></title>
- <url><![CDATA[http://www.oschina.net/p/wh-app-ios]]></url>
- <pubDate></pubDate>
- <author></author>
- </result>
- <result>
- <objid>17045</objid>
- <type>software</type>
- <title><![CDATA[iPhone操作系统 iOS]]></title>
- <url><![CDATA[http://www.oschina.net/p/ios]]></url>
- <pubDate></pubDate>
- <author></author>
- </result>
- <result>
- <objid>25685</objid>
- <type>software</type>
- <title><![CDATA[iOS 弹出菜单 MLPPopupMenu]]></title>
- <url><![CDATA[http://www.oschina.net/p/mlppopupmenu]]></url>
- <pubDate></pubDate>
- <author></author>
- </result>
- <result>
- <objid>22803</objid>
- <type>software</type>
- <title><![CDATA[iOS日历控件 PMCalendar]]></title>
- <url><![CDATA[http://www.oschina.net/p/pmcalendar]]></url>
- <pubDate></pubDate>
- <author></author>
- </result>
- <result>
- <objid>24390</objid>
- <type>software</type>
- <title><![CDATA[iOS 功能测试框架 calabash-ios]]></title>
- <url><![CDATA[http://www.oschina.net/p/calabash-ios]]></url>
- <pubDate></pubDate>
- <author></author>
- </result>
- <result>
- <objid>24665</objid>
- <type>software</type>
- <title><![CDATA[ iOS-Tree-Component]]></title>
- <url><![CDATA[http://www.oschina.net/p/ios-tree-component]]></url>
- <pubDate></pubDate>
- <author></author>
- </result>
- <result>
- <objid>22217</objid>
- <type>software</type>
- <title><![CDATA[ ios-calendar]]></title>
- <url><![CDATA[http://www.oschina.net/p/ios-calendar]]></url>
- <pubDate></pubDate>
- <author></author>
- </result>
- <result>
- <objid>22380</objid>
- <type>software</type>
- <title><![CDATA[ PaperFold-for-iOS]]></title>
- <url><![CDATA[http://www.oschina.net/p/paperfold-for-ios]]></url>
- <pubDate></pubDate>
- <author></author>
- </result>
- <result>
- <objid>21763</objid>
- <type>software</type>
- <title><![CDATA[ drupal-ios-sdk]]></title>
- <url><![CDATA[http://www.oschina.net/p/drupal-ios-sdk]]></url>
- <pubDate></pubDate>
- <author></author>
- </result>
- <result>
- <objid>19628</objid>
- <type>software</type>
- <title><![CDATA[iOS开发基础工具包 BaseAppKit]]></title>
- <url><![CDATA[http://www.oschina.net/p/baseappkit]]></url>
- <pubDate></pubDate>
- <author></author>
- </result>
- <result>
- <objid>20637</objid>
- <type>software</type>
- <title><![CDATA[iOS消息提醒库 TBHintView]]></title>
- <url><![CDATA[http://www.oschina.net/p/tbhintview]]></url>
- <pubDate></pubDate>
- <author></author>
- </result>
- <result>
- <objid>21246</objid>
- <type>software</type>
- <title><![CDATA[iOS 弹出式菜单 MGTileMenu]]></title>
- <url><![CDATA[http://www.oschina.net/p/mgtilemenu]]></url>
- <pubDate></pubDate>
- <author></author>
- </result>
- <result>
- <objid>23498</objid>
- <type>software</type>
- <title><![CDATA[iOS 的 Canvas 和 Audio 实现 Ejecta]]></title>
- <url><![CDATA[http://www.oschina.net/p/ejecta]]></url>
- <pubDate></pubDate>
- <author></author>
- </result>
- <result>
- <objid>23968</objid>
- <type>software</type>
- <title><![CDATA[样式化 iOS 应用 NUI]]></title>
- <url><![CDATA[http://www.oschina.net/p/nui]]></url>
- <pubDate></pubDate>
- <author></author>
- </result>
- <result>
- <objid>20730</objid>
- <type>software</type>
- <title><![CDATA[iOS/Android 矢量图形框架 TouchVG]]></title>
- <url><![CDATA[http://www.oschina.net/p/touchvg]]></url>
- <pubDate></pubDate>
- <author></author>
- </result>
- <result>
- <objid>22356</objid>
- <type>software</type>
- <title><![CDATA[iOS日历控件 MACalendarUI]]></title>
- <url><![CDATA[http://www.oschina.net/p/macalendarui]]></url>
- <pubDate></pubDate>
- <author></author>
- </result>
- </results>
- <notice>
- <atmeCount>0</atmeCount>
- <msgCount>0</msgCount>
- <reviewCount>0</reviewCount>
- <newFansCount>0</newFansCount>
- </notice>
- </oschina>
- <!-- Generated by OsChina.NET (init:0[ms],page:13[ms],ip:61.163.231.198) -->
要解析xm里数据必须熟悉xml文件各个节点之间关系
根节点oschina,它的子节点pagesize返回本次加载了几条数据,子节点results,results的子节点下20条result节点,我们主要获取result内容。然后就是最后面的子节点notice节点,存放用户的一些信息如动弹情况、收到消息、回复、粉丝;在post请求中用到了一个异常处理语句 @try @catch @finally
@try
{
//执行的代码,其中可能有异常。一旦发现异常,则立即跳到catch执行。否则不会执行catch里面的内容
}
@catch
{
//除非try里面执行代码发生了异常,否则这里的代码不会执行
}
@finally
{
//不管什么情况都会执行,包括try catch 里面用了return ,可以理解为只要执行了try或者catch,就一定会执行 finally
}
给dosearch添加了一些注释
[cpp] view plaincopy
- -(void)doSearch
- {
- // 标记,表示正在加载数据中
- isLoading = YES;
- NSString * catalog;
- // switch语句中根据Segment按钮集合中按钮索引,判断搜索哪一类内容,为下面的搜索API传参
- switch (self.segmentSearch.selectedSegmentIndex) {
- case 0:
- catalog = @"software";
- break;
- case 1:
- catalog = @"post";
- break;
- case 2:
- catalog = @"blog";
- break;
- case 3:
- catalog = @"news";
- break;
- }
- //使用AFNetWork使用post方式从网络请求数据
- [[AFOSCClient sharedClient] postPath:api_search_list parameters:[NSDictionary dictionaryWithObjectsAndKeys:_searchBar.text,@"content",catalog,@"catalog",[NSString stringWithFormat:@"%d", allCount/20],@"pageIndex",@"20",@"pageSize", nil] success:^(AFHTTPRequestOperation *operation, id responseObject) {
- // 取消searchBar的第一响应对象,键盘消失
- [self._searchBar resignFirstResponder];
- // 在没有内容之前tableView是没有任何内容的,所以隐藏掉
- self.tableResult.hidden = NO;
- // 根据请求回来的数据判断当前用户释放登陆,需要获取用户一些信息
- [Tool getOSCNotice2:operation.responseString];
- // 上面属于请求数据是不回加载到视图控制器上,所以标记属性为NO
- isLoading = NO;
- // 再次从xml文件中请求数据,获取当前加载数据条数,数量
- int count = [Tool isListOver2:operation.responseString];
- allCount += count;
- // 将请求的xml内容给NSString对象
- NSString *response = operation.responseString;
- NSLog(@"response =%@",response);
- @try {
- // 开始解析需要显示到表视图单元格对象中的数据
- TBXML *xml = [[TBXML alloc] initWithXMLString:response error:nil];
- TBXMLElement *root = xml.rootXMLElement;
- // 从次根节点获取根节点下内容
- TBXMLElement *_results = [TBXML childElementNamed:@"results" parentElement:root];
- if (!_results) {
- isLoadOver = YES;
- [self.tableResult reloadData];
- return;
- }
- // 获取result节点下内容
- TBXMLElement *first = [TBXML childElementNamed:@"result" parentElement:_results];
- if (!first) {
- isLoadOver = YES;
- [self.tableResult reloadData];
- return;
- }
- // 取出result节点下的节点
- NSMutableArray * newResults = [[NSMutableArray alloc] initWithCapacity:20];
- TBXMLElement *objid = [TBXML childElementNamed:@"objid" parentElement:first];
- TBXMLElement *type = [TBXML childElementNamed:@"type" parentElement:first];
- TBXMLElement *title = [TBXML childElementNamed:@"title" parentElement:first];
- TBXMLElement *url = [TBXML childElementNamed:@"url" parentElement:first];
- TBXMLElement *pubDate = [TBXML childElementNamed:@"pubDate" parentElement:first];
- NSString * pubDateStr = [TBXML textForElement:pubDate];
- TBXMLElement *author = [TBXML childElementNamed:@"author" parentElement:first];
- // 取出节点中的值,赋给一个SearchResult对象属性
- SearchResult * s = [[SearchResult alloc] initWithParameters:[[TBXML textForElement:objid] intValue] andType:[[TBXML textForElement:type] intValue] andTitle:[TBXML textForElement:title] andUrl:[TBXML textForElement:url] andPubDate:[pubDateStr isEqualToString:@""] ? @"" : [Tool intervalSinceNow:pubDateStr] andAuthor:[TBXML textForElement:author]];
- // 将获取对象添加到可变数组
- if (![Tool isRepeatSearch:results andResult:s]) {
- [newResults addObject:s];
- }
- // 在循环之中 寻找下一个节点 直至找完
- while (first) {
- first = [TBXML nextSiblingNamed:@"result" searchFromElement:first];
- if (first) {
- objid = [TBXML childElementNamed:@"objid" parentElement:first];
- type = [TBXML childElementNamed:@"type" parentElement:first];
- title = [TBXML childElementNamed:@"title" parentElement:first];
- url = [TBXML childElementNamed:@"url" parentElement:first];
- pubDate = [TBXML childElementNamed:@"pubDate" parentElement:first];
- author = [TBXML childElementNamed:@"author" parentElement:first];
- s = [[SearchResult alloc] initWithParameters:[[TBXML textForElement:objid] intValue] andType:[[TBXML textForElement:type] intValue] andTitle:[TBXML textForElement:title] andUrl:[TBXML textForElement:url] andPubDate:[Tool intervalSinceNow:[TBXML textForElement:pubDate]] andAuthor:[TBXML textForElement:author]];
- //
- if (![Tool isRepeatSearch:results andResult:s]) {
- [newResults addObject:s];
- }
- }
- // first = NULL 直接跳出
- else
- {
- break;
- }
- }
- // 如果搜索结果数据小雨20条,表示一个页面就可以加载完毕
- if (newResults.count < 20) {
- isLoadOver = YES;
- }
- // 将解析数据添加道results之中
- [results addObjectsFromArray:newResults];
- // 刷新表示图内容
- [self.tableResult reloadData];
- }
- @catch (NSException *exception) {
- [NdUncaughtExceptionHandler TakeException:exception];
- }
- @finally {
- }
- // 请求失败
- } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
- [Tool ToastNotification:@"网络连接故障" andView:self.view andLoading:NO andIsBottom:NO];
- }];
- // 刷新表视图单元内容
- [self.tableResult reloadData];
- }
在 [Tool getOSCNotice2:operation.responseString];解析的登陆用户一些信息
// Tool类中
[cpp] view plaincopy
- + (OSCNotice *)getOSCNotice2:(NSString *)response
- {
- TBXML *xml = [[TBXML alloc] initWithXMLString:response error:nil];
- TBXMLElement *root = xml.rootXMLElement;
- if (!root) {
- return nil;
- }
- TBXMLElement *notice = [TBXML childElementNamed:@"notice" parentElement:root];
- if (!notice) {
- [Config Instance].isLogin = NO;
- [[NSNotificationCenter defaultCenter] postNotificationName:@"login" object:@"0"];
- return nil;
- }
- else
- {
- [[NSNotificationCenter defaultCenter] postNotificationName:@"login" object:@"1"];
- [Config Instance].isLogin = YES;
- }
- TBXMLElement *atme = [TBXML childElementNamed:@"atmeCount" parentElement:notice];
- TBXMLElement *msg = [TBXML childElementNamed:@"msgCount" parentElement:notice];
- TBXMLElement *review = [TBXML childElementNamed:@"reviewCount" parentElement:notice];
- TBXMLElement *newFans = [TBXML childElementNamed:@"newFansCount" parentElement:notice];
- OSCNotice *oc = [[OSCNotice alloc] initWithParameters:[[TBXML textForElement:atme] intValue] andMsg:[[TBXML textForElement:msg] intValue] andReview:[[TBXML textForElement:review] intValue] andFans:[[TBXML textForElement:newFans] intValue]];
- [[NSNotificationCenter defaultCenter] postNotificationName:Notification_NoticeUpdate object:oc];
- return oc;
- }
[Tool isListOver2:operation.responseString]; 用于也是解析数据,获取返回的数据条数,告诉table将要显示多少行cell,当把cell加载到最后的时候获取下面20项,或跟多,然后把这些数据存放道allcount里面,所以就有allCount += count
Tool类中,解析返回一个数据 pagesize,显示多少行
[cpp] view plaincopy
- + (int)isListOver2:(NSString *)response
- {
- TBXML *xml = [[TBXML alloc] initWithXMLString:response error:nil];
- TBXMLElement *root = xml.rootXMLElement;
- TBXMLElement *pageSize = [TBXML childElementNamed:@"pagesize" parentElement:root];
- int size = [[TBXML textForElement:pageSize] intValue];
- return size;
- }
然后进入到try中又一次解析获取result里面数据,这里有请求了一次数据,有解析了一边,感觉这里处理的不是很好,同一个返回数据请求了三次,如果用户用的不是wifi就可能耗费流量浪费电量;
剩下的就是表示图加载数据了
[cpp] view plaincopy
- -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
- {
- // 如何加载完成,返回数据为空,返回1,这个单元格是显示一个提示,“查无结果” 如果返回不为空,返回results.count + 1 个显示结果,最后加 1 ,是显示加载数据超过20条的时候 点击 “下面20项”时加载更多数据
- if (isLoadOver) {
- return results.count == 0 ? 1 : results.count;
- }
- else
- return results.count + 1;
- }
- //处理cell的行高
- -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
- {
- if (isLoadOver) {
- return results.count == 0 ? 62 : 50;
- }
- else
- {
- return indexPath.row < results.count ? 50 : 62;
- }
- }
- //处理tableView背景色
- -(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
- {
- cell.backgroundColor = [Tool getCellBackgroundColor];
- }
- //定制单元格的显示内容
- -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
- {
- if (results.count > 0)
- {
- if (indexPath.row < results.count)
- {
- UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:NormalCellIdentifier];
- if (!cell) {
- cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:NormalCellIdentifier];
- }
- SearchResult * s = [results objectAtIndex:indexPath.row];
- cell.textLabel.font = [UIFont boldSystemFontOfSize:15.0];
- cell.textLabel.text = s.title;
- if (self.segmentSearch.selectedSegmentIndex != 0)
- {
- cell.detailTextLabel.text = [NSString stringWithFormat:@"%@ 发表于 %@", s.author, s.pubDate];
- }
- else
- {
- cell.detailTextLabel.text = @"";
- }
- cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
- return cell;
- }
- else
- {
- return [[DataSingleton Instance] getLoadMoreCell:tableView andIsLoadOver:isLoadOver andLoadOverString:@"搜索完毕" andLoadingString:(isLoading ? loadingTip : loadNext20Tip) andIsLoading:isLoading];
- }
- }
- // 如果搜索返回的数据为空 提示 查无结果
- else
- {
- return [[DataSingleton Instance] getLoadMoreCell:tableView andIsLoadOver:isLoadOver andLoadOverString:@"查无结果" andLoadingString:(isLoading ? loadingTip : loadNext20Tip) andIsLoading:isLoading];
- }
- }
- //选中某一行的时候显示该条信息的详细内容
- -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
- {
- [self._searchBar resignFirstResponder];
- [tableView deselectRowAtIndexPath:indexPath animated:YES];
- int row = indexPath.row;
- if (row >= results.count)
- {
- if (!isLoading && !isLoadOver)
- {
- [self performSelector:@selector(doSearch)];
- }
- }
- else
- {
- SearchResult * s = [results objectAtIndex:row];
- if (s)
- {
- [Tool analysis:s.url andNavController:self.navigationController];
- }
- }
- }
打开某一条信息,并查看其详细信息调用 analysis: andNavController:,该方法里针对传入URL,如果是站外连接 比如某个软件官网,直接跳转到该软件的官网上,如果是开源中国社区站内连接,就可能需要加载一些这条信息的评论详情如果检测道用户登陆给予用户品论权限和分享功能;具体实现如下
[cpp] view plaincopy
- + (BOOL)analysis:(NSString *)url andNavController:(UINavigationController *)navController
- {
- NSString *search = @"oschina.net";
- //判断是否包含 oschina.net 来确定是不是站内链接
- NSRange rng = [url rangeOfString:search];
- if (rng.length <= 0) {
- [[UIApplication sharedApplication] openURL:[NSURL URLWithString:url]];
- return NO;
- }
- //站内链接
- else
- {
- url = [url substringFromIndex:7];
- NSString *prefix = [url substringToIndex:3];
- //此情况为 博客,动弹,个人专页
- if ([prefix isEqualToString:@"my."])
- {
- NSArray *array = [url componentsSeparatedByString:@"/"];
- //个人专页 用户名形式
- if ([array count] <= 2) {
- [Tool pushUserDetailWithName:[array objectAtIndex:1] andNavController:navController];
- return YES;
- }
- //个人专页 uid形式
- else if([array count] <= 3)
- {
- if ([[array objectAtIndex:1] isEqualToString:@"u"]) {
- [Tool pushUserDetail:[[array objectAtIndex:2] intValue] andNavController:navController];
- return YES;
- }
- }
- else if([array count] <= 4)
- {
- NSString *type = [array objectAtIndex:2];
- if ([type isEqualToString:@"blog"]) {
- News *n = [[News alloc] init];
- n.newsType = 3;
- n.attachment = [array objectAtIndex:3];
- [Tool pushNewsDetail:n andNavController:navController andIsNextPage:NO];
- return YES;
- }
- else if([type isEqualToString:@"tweet"]){
- Tweet *t = [[Tweet alloc] init];
- t._id = [[array objectAtIndex:3] intValue];
- [Tool pushTweetDetail:t andNavController:navController];
- return YES;
- }
- }
- else if(array.count <= 5)
- {
- NSString *type = [array objectAtIndex:3];
- if ([type isEqualToString:@"blog"]) {
- News *n = [[News alloc] init];
- n.newsType = 3;
- n.attachment = [array objectAtIndex:4];
- [Tool pushNewsDetail:n andNavController:navController andIsNextPage:NO];
- return YES;
- }
- }
- }
- //此情况为 新闻,软件,问答
- else if([prefix isEqualToString:@"www"])
- {
- NSArray *array = [url componentsSeparatedByString:@"/"];
- int count = [array count];
- if (count>=3) {
- NSString *type = [array objectAtIndex:1];
- if ([type isEqualToString:@"news"]) {
- int newsid = [[array objectAtIndex:2] intValue];
- News *n = [[News alloc] init];
- n.newsType = 0;
- n._id = newsid;
- [Tool pushNewsDetail:n andNavController:navController andIsNextPage:YES];
- return YES;
- }
- else if([type isEqualToString:@"p"]){
- News *n = [[News alloc] init];
- n.newsType = 1;
- n.attachment = [array objectAtIndex:2];
- [Tool pushNewsDetail:n andNavController:navController andIsNextPage:NO];
- return YES;
- }
- else if([type isEqualToString:@"question"]){
- if (count == 3) {
- NSArray *array2 = [[array objectAtIndex:2] componentsSeparatedByString:@"_"];
- if ([array2 count] >= 2) {
- int _id = [[array2 objectAtIndex:1] intValue];
- Post *p = [[Post alloc] init];
- p._id = _id;
- [Tool pushPostDetail:p andNavController:navController];
- return YES;
- }
- }
- else if(count >= 4)
- {
- // NSString *tag = [array objectAtIndex:3];
- NSString *tag = @"";
- if (array.count == 4) {
- tag = [array objectAtIndex:3];
- }
- else
- {
- for (int i=3; i<count-1; i++) {
- tag = [NSString stringWithFormat:@"%@/%@", [array objectAtIndex:i],[array objectAtIndex:i+1]];
- }
- }
- NSString *tag2 = [tag stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
- PostsView *pview = [PostsView new];
- pview.tag = tag;
- pview.navigationItem.title = [NSString stringWithFormat:@"%@", tag2];
- [navController pushViewController:pview animated:YES];
- return YES;
- }
- }
- }
- }
- // 根据一个URL打开一个网页
- [[UIApplication sharedApplication] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://%@", url]]];
- return NO;
- }
- }
原创博客欢迎转载分享,请注明出处http://blog.csdn.net/duxinfeng2010
分类: 菜鸟学iOS的笔记
2013-05-22 16:35 7278人阅读 评论(6) 收藏 举报
上一篇博客 开源中国iOS客户端学习——(十一)AES加密 中提到将用户名和密码保存到了本地沙盒之中,在从本地读取用户名和密码,这是一个怎样的过程?
[cpp] view plaincopy
- -(void)saveUserNameAndPwd:(NSString *)userName andPwd:(NSString *)pwd
- {
- NSUserDefaults * settings = [NSUserDefaults standardUserDefaults];
- [settings removeObjectForKey:@"UserName"];
- [settings removeObjectForKey:@"Password"];
- [settings setObject:userName forKey:@"UserName"];
- pwd = [AESCrypt encrypt:pwd password:@"pwd"];
- [settings setObject:pwd forKey:@"Password"];
- [settings synchronize];
- }
上面的方法使用了NSUserDefaults类,它也是以字典形式实现对数据功能,并将这些数据保存到本地应用程序沙盒之中,这种方法适合保存较小的数据,例如用户登陆配置信息;这段代码首先是定义了一个对象,进行初始化,移除键值为UseName和Password的对象,防止数据混乱造成干扰;然后就是重新设置键值信息; [settings synchronize];将键值信息同步道本地;
现在我们道沙盒中来看看这个用户配置信息
首先查看应用程序沙盒的路径 ,使用
[cpp] view plaincopy
[cpp] view plaincopy
- <span style="font-family:Comic Sans MS;font-size:18px;"> NSString *homeDirectory = NSHomeDirectory();
- NSLog(@"path:%@", homeDirectory);</span>
打印结果: path:/Users/DolBy/Library/Application Support/iPhone Simulator/5.1/Applications/55C49712-AD95-49E0-B3B9-694DC7D26E94
但是在我的DolBy用户下并没有Library这个目录,这是因为系统隐藏了这些文件目录,现在需要显示这些隐藏的文件,打开终端输入 defaults write com.apple.finder AppleShowAllFiles -bool true 回车,然后重启Finder(不会?请看 查看iOS沙盒(SanBox)文件),找到55C49712-AD95-49E0-B3B9-694DC7D26E94目录下的Library/Preferences下的 net.oschina.iosapp.plist文件,将其打开
从中不难看出保存在本地沙盒中用户的一些基本信息,以及一些配置信息,还记录一些上次获取数据时间等等;
登陆类在Setting目录下的loginView类,先看看loginView.xib吧,界面比较简陋,可能是缺美工吧;
从头文件中声明部分
[cpp] view plaincopy
- #import <UIKit/UIKit.h>
- #import "Tool.h"
- #import "ProfileBase.h"
- #import "MessageView.h"
- #import "Config.h"
- #import "MBProgressHUD.h"
- #import "MyThread.h"
- @interface LoginView : UIViewController<UIWebViewDelegate>
- {
- // ASI类库,获取网络请求,进行登陆验证
- ASIFormDataRequest *request;
- }
- //接受用户名输入
- @property (strong, nonatomic) IBOutlet UITextField *txt_Name;
- //接受用户属于密码
- @property (strong, nonatomic) IBOutlet UITextField *txt_Pwd;
- //开关按钮,设置用户是否要记住用户名和密码
- @property (strong, nonatomic) IBOutlet UISwitch *switch_Remember;
- //标记作用,用于记录请求数据返回异常或错误时是否弹出一个警告
- @property BOOL isPopupByNotice;
- //webView,布局一个手机上的web网页,显示说明信息,在这个web页面有富文本使用,直接可以跳转到url上
- @property (strong, nonatomic) IBOutlet UIWebView *webView;
- //登陆处理
- - (IBAction)click_Login:(id)sender;
- //取消两个textFile的第一响应对象
- - (IBAction)textEnd:(id)sender;
- //取消键盘第一响应对象,点击页面推出键盘
- - (IBAction)backgrondTouch:(id)sender;
- //根据返回的数据保存用户名和用户ID到本地
- - (void)analyseUserInfo:(NSString *)xml;
- @end
在实现文件里,粘贴上主要方法代码
[cpp] view plaincopy
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- [Tool clearWebViewBackground:webView];
- [self.webView setDelegate:self];
- self.navigationItem.title = @"登录";
- //决定是否显示用户名以及密码
- NSString *name = [Config Instance].getUserName;
- NSString *pwd = [Config Instance].getPwd;
- // 如果用户名和密码存在,且不为空,取出付给相应text
- if (name && ![name isEqualToString:@""]) {
- self.txt_Name.text = name;
- }
- if (pwd && ![pwd isEqualToString:@""]) {
- self.txt_Pwd.text = pwd;
- }
- UIBarButtonItem *btnLogin = [[UIBarButtonItem alloc] initWithTitle:@"登录" style:UIBarButtonItemStyleBordered target:self action:@selector(click_Login:)];
- self.navigationItem.rightBarButtonItem = btnLogin;
- self.view.backgroundColor = [Tool getBackgroundColor];
- self.webView.backgroundColor = [Tool getBackgroundColor];
- // web控件上信息
- NSString *html = @"<body style='1, 您可以在 <a href='http://www.oschina.net'>http://www.oschina.net</a> 上免费注册一个账号用来登陆<p />2, 如果您的账号是使用OpenID的方式注册的,那么建议您在网页上为账号设置密码<p />3, 您可以点击 <a href='http://www.oschina.net/question/12_52232'>这里</a> 了解更多关于手机客户端登录的问题</body>";
- [self.webView loadHTMLString:html baseURL:nil];
- self.webView.hidden = NO;
- }
在 [ToolclearWebViewBackground:webView];作用描述不好,直接看方法
[cpp] view plaincopy
- + (void)clearWebViewBackground:(UIWebView *)webView
- {
- UIWebView *web = webView;
- for (id v in web.subviews) {
- if ([v isKindOfClass:[UIScrollView class]]) {
- [v setBounces:NO];
- }
- }
- }
[v setBounces:NO]; 如果[v setBounces:YES]; 滚动上下滚动是出现空隙,不美观,为NO 时就不会;
[cpp] view plaincopy
- - (IBAction)click_Login:(id)sender
- {
- // 获取用户名和密码
- NSString *name = self.txt_Name.text;
- NSString *pwd = self.txt_Pwd.text;
- // 使用ASI类库请求登陆API,
- request = [ASIFormDataRequest requestWithURL:[NSURL URLWithString:api_login_validate]];
- [request setUseCookiePersistence:YES];
- [request setPostValue:name forKey:@"username"];
- [request setPostValue:pwd forKey:@"pwd"];
- [request setPostValue:@"1" forKey:@"keep_login"];
- [request setDelegate:self];
- // 失败调用 requestFailed:
- [request setDidFailSelector:@selector(requestFailed:)];
- // 成功调用 equestLogin:
- [request setDidFinishSelector:@selector(requestLogin:)];
- // 开始请求
- [request startAsynchronous];
- // 动画提示用户等待
- request.hud = [[MBProgressHUD alloc] initWithView:self.view];
- [Tool showHUD:@"正在登录" andView:self.view andHUD:request.hud];
- }
[cpp] view plaincopy
[cpp] view plaincopy
- // 登陆失败,隐藏显示的动画
- - (void)requestFailed:(ASIHTTPRequest *)request
- {
- if (request.hud) {
- [request.hud hide:YES];
- }
- }
[cpp] view plaincopy
- - (void)requestLogin:(ASIHTTPRequest *)request
- {
- if (request.hud) {
- [request.hud hide:YES];
- }
- // 根据请求回来的xml进行解析数据,判断是否登陆成功
- [Tool getOSCNotice:request];
- // 将请求回来的信息保存在客户端
- [request setUseCookiePersistence:YES];
- ApiError *error = [Tool getApiError:request];
- if (error == nil) {
- [Tool ToastNotification:request.responseString andView:self.view andLoading:NO andIsBottom:NO];
- }
- switch (error.errorCode) {
- case 1:
- {
- [[Config Instance] saveCookie:YES];
- if (isPopupByNotice == NO)
- {
- NSUserDefaults *d= [NSUserDefaults standardUserDefaults];
- [self.navigationController popViewControllerAnimated:YES];
- }
- //处理是否记住用户名或者密码
- if (self.switch_Remember.isOn)
- {
- [[Config Instance] saveUserNameAndPwd:self.txt_Name.text andPwd:self.txt_Pwd.text];
- }
- //否则需要清空用户名于密码
- else
- {
- [[Config Instance] saveUserNameAndPwd:@"" andPwd:@""];
- }
- //返回的处理
- if ([Config Instance].viewBeforeLogin)
- {
- if([[Config Instance].viewNameBeforeLogin isEqualToString:@"ProfileBase"])
- {
- ProfileBase *_parent = (ProfileBase *)[Config Instance].viewBeforeLogin;
- _parent.isLoginJustNow = YES;
- }
- }
- //开始分析 uid 等等信息
- [self analyseUserInfo:request.responseString];
- //分析是否需要退回
- if (self.isPopupByNotice) {
- [self.navigationController popViewControllerAnimated:YES];
- }
- // 查看startNotice方法可知是一个定时器,每隔60s刷新一下用户信息,是否有新的粉丝或几条评论
- [[MyThread Instance] startNotice];
- }
- break;
- case 0:
- case -1:
- {
- // 返回 当error.errorCode =0 || 1的时候,显示相关错误信息
- [Tool ToastNotification:[NSString stringWithFormat:@"错误 %@",error.errorMessage] andView:self.view andLoading:NO andIsBottom:NO];
- }
- break;
- }
- }
ApiError 这个类看起来可能很迷惑人,它并不完全像字面意思那样指的是错误的api信息,而是根据请求返回来的数字进行判断。如果error.errorCode = 1表示成功返回了用户的数据,0,-1就可能由于服务器网络等原因不能正确返回数据;
在ApiError *error = [Tool getApiError:request];中,打印 request.responseString如下,
[html] view plaincopy
- <?xml version="1.0" encoding="UTF-8"?>
- <oschina>
- <result>
- <errorCode>1</errorCode>
- <errorMessage><![CDATA[登录成功]]></errorMessage>
- </result>
- <user>
- <uid>112617</uid>
- <location><![CDATA[河南 南阳]]></location>
- <name><![CDATA[新风作浪]]></name>
- <followers>1</followers>
- <fans>0</fans>
- <score>1</score>
- <portrait>http://static.oschina.net/uploads/user/56/112617_100.jpg?t=1350377690000</portrait>
- </user>
- <notice>
- <atmeCount>0</atmeCount>
- <msgCount>0</msgCount>
- <reviewCount>0</reviewCount>
- <newFansCount>0</newFansCount>
- </notice>
- </oschina>
- <!-- Generated by OsChina.NET (init:3[ms],page:3[ms],ip:61.163.231.198) -->
在 [self analyseUserInfo:request.responseString]方法中, 根据请求成功返回的xml,解析用户名和UID,保存用户的UID
[cpp] view plaincopy
- - (void)analyseUserInfo:(NSString *)xml
- {
- @try {
- TBXML *_xml = [[TBXML alloc] initWithXMLString:xml error:nil];
- TBXMLElement *root = _xml.rootXMLElement;
- TBXMLElement *user = [TBXML childElementNamed:@"user" parentElement:root];
- TBXMLElement *uid = [TBXML childElementNamed:@"uid" parentElement:user];
- //获取uid
- [[Config Instance] saveUID:[[TBXML textForElement:uid] intValue]];
- }
- @catch (NSException *exception) {
- [NdUncaughtExceptionHandler TakeException:exception];
- }
- @finally {
- }
- }
在后面也看到[[MyThread Instance] startNotice];看看startNotice方法,是一个定时器,每隔60s刷新一下用户信息,是否有新的粉丝或几条评论;
[cpp] view plaincopy
- -(void)startNotice
- {
- if (isRunning) {
- return;
- }
- else {
- timer = [NSTimer scheduledTimerWithTimeInterval:60 target:self selector:@selector(timerUpdate) userInfo:nil repeats:YES];
- isRunning = YES;
- }
- }
[cpp] view plaincopy
- -(void)timerUpdate
- {
- NSString * url = [NSString stringWithFormat:@"%@?uid=%d",api_user_notice,[Config Instance].getUID];
- [[AFOSCClient sharedClient]getPath:url parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
- [Tool getOSCNotice2:operation.responseString];
- } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
- }];
- }
url请求获取的返回的信息(已经登陆情开源中国社区网站的况下)
[html] view plaincopy
- <oschina>
- <notice>
- <atmeCount>0</atmeCount>
- <msgCount>0</msgCount>
- <reviewCount>0</reviewCount>
- <newFansCount>0</newFansCount>
- </notice>
- </oschina>
- <!--
- Generated by OsChina.NET (init:1[ms],page:1[ms],ip:61.163.231.198)
- -->
关于本文提到的几个动画过渡显示效果请看
[Tool showHUD:@"正在登录" andView:self.view andHUD:request.hud]; MBProgressHUD特效
[Tool ToastNotification:[NSString stringWithFormat:@"错误 %@",error.errorMessage] andView:self.view andLoading:NO andIsBottom:NO]; GCDiscreetNotificationView提示视图
Baidu Button BEGIN
开源中国iOS客户端学习——(十三)使用UIWebView控件布局视图
分类: 菜鸟学iOS的笔记
2013-05-27 23:47 3447人阅读 评论(0) 收藏 举报
在上一篇博客 开源中国iOS客户端学习——(十二)用户登陆 中讲到用户登陆界面,loginView.xib布局中我们看到有一个UIWebView控件,但是它并没有加载一个网页,而是显示一些文本信息,其中有一些网址的链接,点击这个链接的时候条找转到该网站,或者点击某个文字标签同样的效果。
再来看看另外一个ViewController,在News/tab下有一个NewDetail类,查看这个ViewController类的xib时又看到WebView控件,同样他也不是用来加载一个网页,而是作为视图布局使用,在开源中国iOS客户端源码中还是不止这两个类中使用webView控件作为布局引擎,在工程文件tab目录下的SinglePost、SoftwareDeatil 、BlogDetail这些类都是这样使用;NewDetail这个类作用用于加载显示一条资讯信息的详细内容;
然后来看看WebView布局界面显示内容,在选中首页综合里资讯某一条的时候,想查看给咨询详情,然后查看一些界面特效:
或许我们会想问什么要使用WebView布局呢,普通的view也一样可以显示,显示文字有ULabel UITextView 显示图片有UIImageView都可以满足,接着向下看。。。
有一些特殊字体颜色,点击他们的时候有的跳转道另一个视图,有的跳转道某一个网站,能够响应用户的交互;当点击TNW 和点击相关文章的某一文章标题时抓取截图示例如下
或许有人已经知道这些都是iOS中的富文本,确实这就是使用Web视图显示富文本;在普通view中不可以使用富文本吗?必然也可以,还有一些第三方类库如RTLabel来支持富文本的使用,在iOS 6为UIKit也带来了富文本的支持。或许显示简单文本标签没问题,但是布局一些复杂的视图就可能比较难搞了,就像在一段文本中对某两字加上超链接,点击两个字跳转道一个网页,如果是单单两个字也不是难题,但是对于使用多条信息使用同一个xib界面布局怎么办?我们并不知道哪些字需要使用富文本加上超链接?这时候webView视图成了最好解决方案,经常我们打开一个网页的时候比如hao123导航,上面有许多文字链接,点击这些文字跳转道相应官网,刚好 WebView也可以加载HTML代码,而且也很简单,但是在View上就有些困难了;
好了 不废话,先看看WebView如何加载某一条资讯的内容,先看看某一篇资讯,返回xml格式 http://www.oschina.net/action/api/news_detail?id=40840,解析body节点中的数据是HTML代码,由WebView加载这些HTML代码,其他标题有对应的url,将解析的标题和url格式化转换成HTML代码加载道webView中;
必然还是先看ViewDidLoad方法
[cpp] view plaincopy
- <span style="font-family:Comic Sans MS;font-size:18px;">- (void)viewDidLoad
- {
- [super viewDidLoad];
- self.tabBarItem.title = @"资讯详情";
- self.tabBarItem.image = [UIImage imageNamed:@"detail"];
- //WebView的背景颜色去除
- [Tool clearWebViewBackground:self.webView];
- self.singleNews = [[SingleNews alloc] init];
- self.navigationController.title = @"资讯详情";
- self.webView.delegate = self;
- [self.webView loadHTMLString:@"" baseURL:nil];
- if ([Config Instance].isNetworkRunning)
- {
- MBProgressHUD *hud = [[MBProgressHUD alloc] initWithView:self.view];
- [Tool showHUD:@"正在加载" andView:self.view andHUD:hud];
- NSString *url = [NSString stringWithFormat:@"%@?id=%d",api_news_detail, newsID];
- [[AFOSCClient sharedClient] getPath:url parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
- [Tool getOSCNotice2:operation.responseString];
- [hud hide:YES];
- self.singleNews = [Tool readStrNewsDetail:operation.responseString];
- if (self.singleNews == nil) {
- [Tool ToastNotification:@"加载失败" andView:self.view andLoading:NO andIsBottom:NO];
- return;
- }
- [self loadData:self.singleNews];
- //如果有网络 则缓存它
- if ([Config Instance].isNetworkRunning)
- {
- [Tool saveCache:1 andID:self.singleNews._id andString:operation.responseString];
- }
- } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
- [hud hide:YES];
- if ([Config Instance].isNetworkRunning) {
- [Tool ToastNotification:@"错误 网络无连接" andView:self.view andLoading:NO andIsBottom:NO];
- }
- }];
- }
- else
- {
- NSString *value = [Tool getCache:1 andID:newsID];
- if (value) {
- self.singleNews = [Tool readStrNewsDetail:value];
- [self loadData:self.singleNews];
- }
- else {
- [Tool ToastNotification:@"错误 网络无连接" andView:self.view andLoading:NO andIsBottom:NO];
- }
- }
- }
- </span>
ViewDidLoad中主要两个方法:
1.[ToolclearWebViewBackground:self.webView];去掉WebView背景色,显示数据的时候就不会觉得他是一个WebView而是一个普通的View视图;
2.[selfloadData:self.singleNews]; 格式化处理字符串,转换成HTML格式,如设置html的背景颜色字体颜色字体大小等,对于HTML也没用很深研究,大概能看懂一点,
[cpp] view plaincopy
- <span style="font-family:Comic Sans MS;font-size:18px;">- (void)loadData:(SingleNews *)n
- {
- [self refreshFavorite:n];
- //通知去修改新闻评论数
- Notification_CommentCount *notification = [[Notification_CommentCount alloc] initWithParameters:self andCommentCount:n.commentCount];
- [[NSNotificationCenter defaultCenter] postNotificationName:Notification_DetailCommentCount object:notification];
- //新闻 主要用于微博分享
- [Config Instance].shareObject = [[ShareObject alloc] initWithParameters:n.title andUrl:n.url];
- //控件更新
- NSString *author_str = [NSString stringWithFormat:@"<a href='http://my.oschina.net/u/%d'>%@</a> 发布于 %@",n.authorid,n.author,n.pubDate];
- NSString *software = @"";
- if ([n.softwarename isEqualToString:@""] == NO) {
- software = [NSString stringWithFormat:@"<div id='oschina_software' style='margin-top:8px;color:#FF0000;font-size:14px;font-weight:bold'>更多关于: <a href='%@'>%@</a> 的详细信息</div>",n.softwarelink, n.softwarename];
- }
- NSString *html = [NSString stringWithFormat:@"<body style='%@<div id='oschina_title'>%@</div><div id='oschina_outline'>%@</div><hr/><div id='oschina_body'>%@</div>%@%@%@</body>",HTML_Style, n.title,author_str, n.body,software,[Tool generateRelativeNewsString:n.relativies],HTML_Bottom];
- NSString *result = [Tool getHTMLString:html];
- [self.webView loadHTMLString:result baseURL:nil];
- }
- </span>
[self loadData:self.singleNews]方法中对HTML特点格式化中
两个宏定义 HTML_Style HTML_Bottom
[cpp] view plaincopy
- <span style="font-family:Comic Sans MS;font-size:18px;">//html头部
- #define HTML_Style @"<style>#oschina_title {color: #000000; margin-bottom: 6px; font-weight:bold;}#oschina_title img{vertical-align:middle;margin-right:6px;}#oschina_title a{color:#0D6DA8;}#oschina_outline {color: #707070; font-size: 12px;}#oschina_outline a{color:#0D6DA8;}#oschina_software{color:#808080;font-size:12px}#oschina_body img {max- 300px;}#oschina_body {font-size:16px;max-300px;line-height:24px;} #oschina_body table{max-300px;}#oschina_body pre { font-size:9pt;font-family:Courier New,Arial;border:1px solid #ddd;border-left:5px solid #6CE26C;background:#f6f6f6;padding:5px;}</style>"
- #define HTML_Bottom @"<div style='margin-bottom:60px'/>"</span>
[ToolgenerateRelativeNewsString:n.relativies] 处理资讯后面相关文章的布局的HTML
[cpp] view plaincopy
- <span style="font-family:Comic Sans MS;font-size:18px;">+ (NSString *)generateRelativeNewsString:(NSArray *)array
- {
- if (array == nil || [array count] == 0) {
- return @"";
- }
- NSString *middle = @"";
- for (RelativeNews *r in array) {
- middle = [NSString stringWithFormat:@"%@<a href=%@ style='text-decoration:none'>%@</a><p/>",middle, r.url, r.title];
- }
- return [NSString stringWithFormat:@"<hr/>相关文章<div style='font-size:14px'><p/>%@</div>", middle];
- }
- </span>
[self.webView loadHTMLString:result baseURL:nil];才是将html格式化成NSString对象后加载道WebView上,还必须处理webView的一个委托方法。
如果委托方法返回YES表示允许UIWebView请求,但是webView用来布局显示自定义内容,应该返回为NO;假如我们点击某个文字超链接或url时就会发送发送给委托方法,基于这个url做出响应;
[cpp] view plaincopy
- <span style="font-family:Comic Sans MS;font-size:18px;">#pragma 浏览器链接处理
- - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
- {
- [Tool analysis:[request.URL absoluteString] andNavController:self.parentViewController.navigationController];
- if ([request.URL.absoluteString isEqualToString:@"about:blank"])
- {
- return YES;
- }
- else
- {
- return NO;
- }
- }</span>
[Tool analysis:[request.URL absoluteString] andNavController:self.parentViewController.navigationController];响应webView中URL,如果这个url不止站内链接就会调用Safair加载这个网址,如果是站内的信息则跳转对于信息视图;详情可查看analysis:l andNavController:实现方法;
if()语句有个判断,如果请求的URL网址是空白,则webView就会加载这个页面,否则不加载这个url request.URL.absoluteString表示获取url完整链接
本篇博客并没讲解多少WebView如何去布局,主要还在于HTML标签的设计,还是请求数据,解析xml,解析出来的数据格式化添加到HTML的标签节点之中,再有WebView去加载显示;
下面的一个示例测试,获取的都是静态文本数据,主要还是看HTML格式,效果图:
示例源码下载地址:http://duxinfeng.blog.51cto.com/ext/down_att.php?aid=39211&code=8162
原创博客欢迎转载分享,请注明出处http://blog.csdn.net/duxinfeng2010
Baidu Button END 192.168.100.35
- 上一篇
开源中国iOS客户端学习——(十四)使用EGOImageLoading异步加载图片 - 分类: 菜鸟学iOS的笔记
- 2013-05-31 22:09 3725人阅读 评论(1) 收藏 举报
- EGOImageLoading图片异步加载
- EGOImageLoading 是一个用的比较多的异步加载图片的第三方类库,简化开发过程,我们直接传入图片的url,这个类库就会自动帮我们异步加载和缓存工作;当从网上获取图片时,如果网速慢图片短时间内不能下载下来,可以先用一张本地的图片代替显示,还可以进行其他操作,让图片下载完成后自动替换占位图片而不影响用户体验;
- EGOImageLoading 的GitHub 下载地址: https://github.com/enormego/EGOImageLoading
- GitHub上下载下来的类库会有一个Demo,如果运行出错说明缺少EGOCache类,在https://github.com/enormego/EGOCache添加道工程之中,或者直接点击这里下载
- 首先还是来分析一下开源中国iOS客户端如何使用这个第三方类库
- 在我搜索客户端中哪些类使用了这个类库的时候和预期的并不一样,在工程中有很多地方需要使用到图片的异步加载,而使用EGOImageLoading类库加载只有三个地方,也可以说是两个地方
- 一是在显示个人资料加载个人图片,显示个人信息时候使用的。
- 二个是显示你的粉丝或者你关注的人,想查看TA的资料的时候
- 在MyView类和UserView2类中,使用方法一样
- 声明一个 EGOImageView管理图片的异步加载
- [cpp] view plaincopy
- @property (strong,nonatomic) EGOImageView * egoImgView;
- 在ViewDidLoad方法中
- [cpp] view plaincopy
- // 初始化
- self.egoImgView = [[EGOImageView alloc] initWithFrame:CGRectMake(15, 4, 70, 70)];
- // 占位图片
- self.egoImgView.image = [UIImage imageNamed:@"big_avatar_loading.png"];
- // 设置图片圆角弧度
- egoImgView.layer.cornerRadius = 40.0f;
- [self.view addSubview:self.egoImgView];
- 然后就是在reload()方法中图片加载处理,先从网络解析获取图片的url资源,如果未获取到图片url仍然显示占位图片,如果获取到了就将占位图片更换为解析获取的图片
- [cpp] view plaincopy
- //头像
- NSString *portrait_str = [TBXML textForElement:portrait];
- if ([portrait_str isEqualToString:@""])
- {
- self.egoImgView.image = [UIImage imageNamed:@"big_avatar.png"];
- }
- else
- {
- self.egoImgView.imageURL = [NSURL URLWithString:portrait_str];
- }
- 以上就是使用EGOImageLoading 类库进行图片的异步加载;
- 以下是一个使用EGOImageLoading 类库进行图片异步加载的示例Demo
- 下载地址:http://download.csdn.net/detail/duxinfeng2010/5492125
- 在开源中国iOS 客户端的问答、动弹、我的三个视图也涉及到图片的显示加载问题,刚开始误以为使用EGOImageLoading 类库异步加载图片,而实际上是一个延迟加载,先用占位图片显示,然后使用IconDownloader类库从服务器端将图片下载到本地缓存,在进行加载显示;
- 原创博客欢迎转载分享,请注明出处http://blog.csdn.net/duxinfeng2010
- Baidu Button BEGIN
- Baidu Button END 192.168.100.33
- 上一篇
下一篇
Baidu Button BEGIN Baidu Button END
- 顶
-
Baidu Button END 192.168.100.35
分类: 菜鸟学iOS的笔记
2013-06-02 22:13 12032人阅读 评论(2) 收藏 举报
目录(?)
[+]
在一个项目开发过程中为了更好的体验经常会用到下拉刷新更新数据,当然也伴随一些上拉加载更多数据的情况;当前比较火的EGOTableViewPullRefresh只实现了下拉功能,而没有上拉的功能。这里介绍一个同时集成下拉刷新和上拉加载更多的类库EGOTableViewPullRefresh
英文原文和类库下载地址:https://github.com/emreberge/EGOTableViewPullRefresh
附带 Demo效果
Whats different on this fork:
- 容易集成,使用interface builder 添加tableView进行配置。
- 配置简单, 箭头头像,背景颜色和文本颜色都能通过PullTableView类的属性很容易的更改。
- 上拉加载更多数据功能在Table的底部。
- 可以通过代码修改刷新和加载更多动画。
The fast setup:
- 添加 QuartzCore.framework 到你的工程中。
- 将 EGOTableViewPullRefresh 拖到你的工程目录下。
- 查看 PullTableView.h 文件可用的属性。
- 添加一个PullTableView 到你代码中,实现PullTableViewDelegate委托方法。
- 欣赏吧。
The detailed setup (Walk through for creating the demo project):
- 创建一个新的xcode工程
- 选择 View Based Application 模板(xcode 4.2以后版本是 Single View Application模板)
- 工程名字 EGOTableViewPullRefreshDemo
- 在工程文件下创建EGOTableViewPullRefreshDemoViewController控制器类(Single View Application模板不需这步)
- 添加 QuartzCore.framework 到工程中
添加 PullTableView 到工程里:
- 拖拽 EGOTableViewPullRefresh 目录下文件到工程支持的文件组下,确保(EGOTableViewPullRefresh)下文件都拷贝到目标文件组下。
添加 PullTable 视图到 EGOTableViewPullRefreshDemoViewController.xib上:
- 拖一个UITableView控件到View视图上.
- 打开 Identity inspector 将Table 的继承类由 UITableView 改成PullTableView
- 连接 dataSources数据源和 pullDelegate协议到PullTableView的 File's owner上
配置视图控制器的头文件 EGOTableViewPullRefreshDemoViewController.h:
- 添加 #import "PullTableView.h"
- 声明 PullTableViewDelegate 和 UITableViewDataSource协议
- 创建一个属性名为pullTableView的输出口连接到interface Builder上的tableView上
配置视图控制器和页脚 EGOTableViewPullRefreshDemoViewController.m
- 在.m文件中添加下面代码
[cpp] view plaincopy
- #pragma mark - Refresh and load more methods
- - (void) refreshTable
- {
- /*
- Code to actually refresh goes here. 刷新代码放在这
- */
- self.pullTableView.pullLastRefreshDate = [NSDate date];
- self.pullTableView.pullTableIsRefreshing = NO;
- }
- - (void) loadMoreDataToTable
- {
- /*
- Code to actually load more data goes here. 加载更多实现代码放在在这
- */
- self.pullTableView.pullTableIsLoadingMore = NO;
- }
- #pragma mark - UITableViewDataSource
- - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
- {
- return 5;
- }
- - (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
- {
- return 10;
- }
- - (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
- {
- static NSString *cellIdentifier = @"Cell";
- UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
- if(!cell) {
- cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
- }
- cell.textLabel.text = [NSString stringWithFormat:@"Row %i", indexPath.row];
- return cell;
- }
- - (NSString *) tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
- {
- return [NSString stringWithFormat:@"Section %i begins here!", section];
- }
- - (NSString *) tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
- {
- return [NSString stringWithFormat:@"Section %i ends here!", section];
- }
- #pragma mark - PullTableViewDelegate
- - (void)pullTableViewDidTriggerRefresh:(PullTableView *)pullTableView
- {
- [self performSelector:@selector(refreshTable) withObject:nil afterDelay:3.0f];
- }
- - (void)pullTableViewDidTriggerLoadMore:(PullTableView *)pullTableView
- {
- [self performSelector:@selector(loadMoreDataToTable) withObject:nil afterDelay:3.0f];
- }
- 对于UI的配置,在ViewDidLoad()方法里面添加下面代码(比如 修改刷新和上拉的背景色箭头头像等)
[cpp] view plaincopy
- self.pullTableView.pullArrowImage = [UIImage imageNamed:@"blackArrow"];
- self.pullTableView.pullBackgroundColor = [UIColor yellowColor];
- self.pullTableView.pullTextColor = [UIColor blackColor];
- 对于手动设置动画可使用 pullTableIsRefreshing 和pullTableIsLoadingMore 属性. 比如在 viewWillAppear:方法里面添加下面的代码
[cpp] view plaincopy
- if(!self.pullTableView.pullTableIsRefreshing) {
- self.pullTableView.pullTableIsRefreshing = YES;
- [self performSelector:@selector(refreshTable) withObject:nil afterDelay:3];
- }
原创博客欢迎转载分享,请注明出处http://blog.csdn.net/duxinfeng2010