*************application

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{// 1.创建窗口self.window = [[UIWindow alloc] init];self.window.frame = [UIScreen mainScreen].bounds;// 2.设置根控制器HWAccount *account = [HWAccountTool account];if (account) { // 之前已经登录成功过
        [self.window switchRootViewController];} else {self.window.rootViewController = [[HWOAuthViewController alloc] init];   //授权登陆的界面}// 3.显示窗口
    [self.window makeKeyAndVisible];return YES;
}

*************存储账号的信息HWAccountTool.m

// 账号的存储路径
#define HWAccountPath [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"account.archive"]#import "HWAccountTool.h"
#import "HWAccount.h"@implementation HWAccountTool/***  存储账号信息**  @param account 账号模型*/
+ (void)saveAccount:(HWAccount *)account
{// 获得账号存储的时间(accessToken的产生时间)account.created_time = [NSDate date];// 自定义对象的存储必须用NSKeyedArchiver,不再有什么writeToFile方法
    [NSKeyedArchiver archiveRootObject:account toFile:HWAccountPath];
}/***  返回账号信息**  @return 账号模型(如果账号过期,返回nil)*/
+ (HWAccount *)account
{// 加载模型HWAccount *account = [NSKeyedUnarchiver unarchiveObjectWithFile:HWAccountPath];/* 验证账号是否过期 */// 过期的秒数long long expires_in = [account.expires_in longLongValue];// 获得过期时间NSDate *expiresTime = [account.created_time dateByAddingTimeInterval:expires_in];// 获得当前时间NSDate *now = [NSDate date];// 如果expiresTime <= now,过期/**NSOrderedAscending = -1L, 升序,右边 > 左边NSOrderedSame, 一样NSOrderedDescending 降序,右边 < 左边*/NSComparisonResult result = [expiresTime compare:now];if (result != NSOrderedDescending) { // 过期return nil;}return account;
}
@end

*******HWAccount.m

#import "HWAccount.h"@implementation HWAccount
+ (instancetype)accountWithDict:(NSDictionary *)dict
{HWAccount *account = [[self alloc] init];account.access_token = dict[@"access_token"];account.uid = dict[@"uid"];account.expires_in = dict[@"expires_in"];return account;
}/***  当一个对象要归档进沙盒中时,就会调用这个方法*  目的:在这个方法中说明这个对象的哪些属性要存进沙盒*/
- (void)encodeWithCoder:(NSCoder *)encoder
{[encoder encodeObject:self.access_token forKey:@"access_token"];[encoder encodeObject:self.expires_in forKey:@"expires_in"];[encoder encodeObject:self.uid forKey:@"uid"];[encoder encodeObject:self.created_time forKey:@"created_time"];
}/***  当从沙盒中解档一个对象时(从沙盒中加载一个对象时),就会调用这个方法*  目的:在这个方法中说明沙盒中的属性该怎么解析(需要取出哪些属性)*/
- (id)initWithCoder:(NSCoder *)decoder
{if (self = [super init]) {self.access_token = [decoder decodeObjectForKey:@"access_token"];self.expires_in = [decoder decodeObjectForKey:@"expires_in"];self.uid = [decoder decodeObjectForKey:@"uid"];self.created_time = [decoder decodeObjectForKey:@"created_time"];}return self;
}
@end

*********HWAccount.h

#import <Foundation/Foundation.h>@interface HWAccount : NSObject <NSCoding>
/** string    用于调用access_token,接口获取授权后的access token。*/
@property (nonatomic, copy) NSString *access_token;/** string    access_token的生命周期,单位是秒数。*/
@property (nonatomic, copy) NSNumber *expires_in;/** string    当前授权用户的UID。*/
@property (nonatomic, copy) NSString *uid;/**    access token的创建时间 */
@property (nonatomic, strong) NSDate *created_time;+ (instancetype)accountWithDict:(NSDictionary *)dict;
@end

**********HWOAuthViewController.m

#import "HWOAuthViewController.h"
#import "AFNetworking.h"
#import "HWAccount.h"
#import "HWAccountTool.h"
#import "MBProgressHUD+MJ.h"@interface HWOAuthViewController () <UIWebViewDelegate>@end@implementation HWOAuthViewController- (void)viewDidLoad
{[super viewDidLoad];// 1.创建一个webViewUIWebView *webView = [[UIWebView alloc] init];webView.frame = self.view.bounds;webView.delegate = self;[self.view addSubview:webView];// 2.用webView加载登录页面(新浪提供的)// 请求地址:https://api.weibo.com/oauth2/authorize/* 请求参数:client_id    true    string    申请应用时分配的AppKey。redirect_uri    true    string    授权回调地址,站外应用需与设置的回调地址一致,站内应用需填写canvas page的地址。*/NSURL *url = [NSURL URLWithString:@"https://api.weibo.com/oauth2/authorize?client_id=3235932662&redirect_uri=http://www.baidu.com"];NSURLRequest *request = [NSURLRequest requestWithURL:url];[webView loadRequest:request];
}#pragma mark - webView代理方法
- (void)webViewDidFinishLoad:(UIWebView *)webView
{[MBProgressHUD hideHUD];
}- (void)webViewDidStartLoad:(UIWebView *)webView
{[MBProgressHUD showMessage:@"正在加载..."];
}- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{[MBProgressHUD hideHUD];
}- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{// 1.获得urlNSString *url = request.URL.absoluteString;// 2.判断是否为回调地址NSRange range = [url rangeOfString:@"code="];if (range.length != 0) { // 是回调地址// 截取code=后面的参数值int fromIndex = range.location + range.length;NSString *code = [url substringFromIndex:fromIndex];// 利用code换取一个accessToken
        [self accessTokenWithCode:code];// 禁止加载回调地址return NO;}return YES;
}/***  利用code(授权成功后的request token)换取一个accessToken**  @param code 授权成功后的request token*/
- (void)accessTokenWithCode:(NSString *)code
{
/*URL:https://api.weibo.com/oauth2/access_token请求参数:client_id:申请应用时分配的AppKeyclient_secret:申请应用时分配的AppSecretgrant_type:使用authorization_coderedirect_uri:授权成功后的回调地址code:授权成功后返回的code*/// 1.请求管理者AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];
//    mgr.responseSerializer = [AFJSONResponseSerializer serializer];// AFN的AFJSONResponseSerializer默认不接受text/plain这种类型// 2.拼接请求参数NSMutableDictionary *params = [NSMutableDictionary dictionary];params[@"client_id"] = @"3235932662";params[@"client_secret"] = @"227141af66d895d0dd8baca62f73b700";params[@"grant_type"] = @"authorization_code";params[@"redirect_uri"] = @"http://www.baidu.com";params[@"code"] = code;// 3.发送请求[mgr POST:@"https://api.weibo.com/oauth2/access_token" parameters:params success:^(AFHTTPRequestOperation *operation, NSDictionary *responseObject) {[MBProgressHUD hideHUD];// 将返回的账号字典数据 --> 模型,存进沙盒HWAccount *account = [HWAccount accountWithDict:responseObject];// 存储账号信息
        [HWAccountTool saveAccount:account];// 切换窗口的根控制器UIWindow *window = [UIApplication sharedApplication].keyWindow;[window switchRootViewController];// UIWindow的分类、HWWindowTool// UIViewController的分类、HWControllerTool} failure:^(AFHTTPRequestOperation *operation, NSError *error) {[MBProgressHUD hideHUD];HWLog(@"请求失败-%@", error);}];
}
@end

UIWindow+Extension.m

#import "UIWindow+Extension.h"
#import "HWTabBarViewController.h"
#import "HWNewfeatureViewController.h"@implementation UIWindow (Extension)
- (void)switchRootViewController
{NSString *key = @"CFBundleVersion";// 上一次的使用版本(存储在沙盒中的版本号)NSString *lastVersion = [[NSUserDefaults standardUserDefaults] objectForKey:key];// 当前软件的版本号(从Info.plist中获得)NSString *currentVersion = [NSBundle mainBundle].infoDictionary[key];if ([currentVersion isEqualToString:lastVersion]) { // 版本号相同:这次打开和上次打开的是同一个版本self.rootViewController = [[HWTabBarViewController alloc] init];} else { // 这次打开的版本和上一次不一样,显示新特性self.rootViewController = [[HWNewfeatureViewController alloc] init];// 将当前的版本号存进沙盒
        [[NSUserDefaults standardUserDefaults] setObject:currentVersion forKey:key];[[NSUserDefaults standardUserDefaults] synchronize];}
}
@end

************HWHomeViewController.m

#import "HWHomeViewController.h"
#import "HWDropdownMenu.h"
#import "HWTitleMenuViewController.h"
#import "AFNetworking.h"
#import "HWAccountTool.h"
#import "HWTitleButton.h"
#import "UIImageView+WebCache.h"
#import "HWUser.h"
#import "HWStatus.h"
#import "MJExtension.h"                     // 第三方的框架@interface HWHomeViewController () <HWDropdownMenuDelegate>
/***  微博数组(里面放的都是HWStatus模型,一个HWStatus对象就代表一条微博)*/
@property (nonatomic, strong) NSMutableArray *statuses;
@end@implementation HWHomeViewController- (NSMutableArray *)statuses
{if (!_statuses) {self.statuses = [NSMutableArray array];}return _statuses;
}- (void)viewDidLoad
{[super viewDidLoad];// 设置导航栏内容
    [self setupNav];// 获得用户信息(昵称)
    [self setupUserInfo];// 集成刷新控件
    [self setupRefresh];
}/*** 3. 集成刷新控件*/
- (void)setupRefresh
{UIRefreshControl *control = [[UIRefreshControl alloc] init];[control addTarget:self action:@selector(refreshStateChange:) forControlEvents:UIControlEventValueChanged];[self.tableView addSubview:control];
}/*** 3-1 UIRefreshControl进入刷新状态:加载最新的数据*/
- (void)refreshStateChange:(UIRefreshControl *)control
{// 1.请求管理者AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];// 2.拼接请求参数HWAccount *account = [HWAccountTool account];NSMutableDictionary *params = [NSMutableDictionary dictionary];params[@"access_token"] = account.access_token;// 取出最前面的微博(最新的微博,ID最大的微博)HWStatus *firstStatus = [self.statuses firstObject];if (firstStatus) {// 若指定此参数,则返回ID比since_id大的微博(即比since_id时间晚的微博),默认为0params[@"since_id"] = firstStatus.idstr;}// 3.发送请求[mgr GET:@"https://api.weibo.com/2/statuses/friends_timeline.json" parameters:params success:^(AFHTTPRequestOperation *operation, NSDictionary *responseObject) {// 将 "微博字典"数组 转为 "微博模型"数组NSArray *newStatuses = [HWStatus objectArrayWithKeyValuesArray:responseObject[@"statuses"]];                 //第三方的框架// 将最新的微博数据,添加到总数组的最前面NSRange range = NSMakeRange(0, newStatuses.count);NSIndexSet *set = [NSIndexSet indexSetWithIndexesInRange:range];[self.statuses insertObjects:newStatuses atIndexes:set];// 刷新表格
        [self.tableView reloadData];// 结束刷新刷新
        [control endRefreshing];} failure:^(AFHTTPRequestOperation *operation, NSError *error) {HWLog(@"请求失败-%@", error);// 结束刷新刷新
        [control endRefreshing];}];
}/*** 2. 获得用户信息(昵称)*/
- (void)setupUserInfo
{// 1.请求管理者AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];// 2.拼接请求参数HWAccount *account = [HWAccountTool account];NSMutableDictionary *params = [NSMutableDictionary dictionary];params[@"access_token"] = account.access_token;params[@"uid"] = account.uid;// 3.发送请求[mgr GET:@"https://api.weibo.com/2/users/show.json" parameters:params success:^(AFHTTPRequestOperation *operation, NSDictionary *responseObject) {// 标题按钮UIButton *titleButton = (UIButton *)self.navigationItem.titleView;// 设置名字HWUser *user = [HWUser objectWithKeyValues:responseObject];[titleButton setTitle:user.name forState:UIControlStateNormal];// 存储昵称到沙盒中account.name = user.name;[HWAccountTool saveAccount:account];} failure:^(AFHTTPRequestOperation *operation, NSError *error) {HWLog(@"请求失败-%@", error);}];
}/*** 1. 设置导航栏内容*/
- (void)setupNav
{/* 设置导航栏上面的内容 */self.navigationItem.leftBarButtonItem = [UIBarButtonItem itemWithTarget:self action:@selector(friendSearch) image:@"navigationbar_friendsearch" highImage:@"navigationbar_friendsearch_highlighted"];self.navigationItem.rightBarButtonItem = [UIBarButtonItem itemWithTarget:self action:@selector(pop) image:@"navigationbar_pop" highImage:@"navigationbar_pop_highlighted"];/* 中间的标题按钮 */HWTitleButton *titleButton = [[HWTitleButton alloc] init];// 设置图片和文字NSString *name = [HWAccountTool account].name;[titleButton setTitle:name?name:@"首页" forState:UIControlStateNormal];// 监听标题点击
    [titleButton addTarget:self action:@selector(titleClick:) forControlEvents:UIControlEventTouchUpInside];self.navigationItem.titleView = titleButton;
}/*** 1-1 标题点击*/
- (void)titleClick:(UIButton *)titleButton
{// 1.创建下拉菜单HWDropdownMenu *menu = [HWDropdownMenu menu];menu.delegate = self;// 2.设置内容HWTitleMenuViewController *vc = [[HWTitleMenuViewController alloc] init];vc.view.height = 150;vc.view.width = 150;menu.contentController = vc;// 3.显示
    [menu showFrom:titleButton];
}- (void)friendSearch
{NSLog(@"friendSearch");
}- (void)pop
{NSLog(@"pop");
}#pragma mark - HWDropdownMenuDelegate
/***  下拉菜单被销毁了*/
- (void)dropdownMenuDidDismiss:(HWDropdownMenu *)menu
{UIButton *titleButton = (UIButton *)self.navigationItem.titleView;// 让箭头向下titleButton.selected = NO;
}/***  下拉菜单显示了*/
- (void)dropdownMenuDidShow:(HWDropdownMenu *)menu
{UIButton *titleButton = (UIButton *)self.navigationItem.titleView;// 让箭头向上titleButton.selected = YES;
}#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{return self.statuses.count;
}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{static NSString *ID = @"status";UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];if (!cell) {cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];}// 取出这行对应的微博字典HWStatus *status = self.statuses[indexPath.row];// 取出这条微博的作者(用户)HWUser *user = status.user;cell.textLabel.text = user.name;// 设置微博的文字cell.detailTextLabel.text = status.text;// 设置头像UIImage *placehoder = [UIImage imageNamed:@"avatar_default_small"];[cell.imageView sd_setImageWithURL:[NSURL URLWithString:user.profile_image_url] placeholderImage:placehoder];return cell;
}/**1.将字典转为模型2.能够下拉刷新最新的微博数据3.能够上拉加载更多的微博数据*/
@end

***HWTitleButton.h

#import "HWTitleButton.h"@implementation HWTitleButton- (id)initWithFrame:(CGRect)frame
{self = [super initWithFrame:frame];if (self) {[self setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];self.titleLabel.font = [UIFont boldSystemFontOfSize:17];[self setImage:[UIImage imageNamed:@"navigationbar_arrow_down"] forState:UIControlStateNormal];[self setImage:[UIImage imageNamed:@"navigationbar_arrow_up"] forState:UIControlStateSelected];}return self;
}- (void)layoutSubviews
{[super layoutSubviews];// 如果仅仅是调整按钮内部titleLabel和imageView的位置,那么在layoutSubviews中单独设置位置即可// 1.计算titleLabel的frameself.titleLabel.x = self.imageView.x;// 2.计算imageView的frameself.imageView.x = CGRectGetMaxX(self.titleLabel.frame);
}- (void)setTitle:(NSString *)title forState:(UIControlState)state
{[super setTitle:title forState:state];// 只要修改了文字,就让按钮重新计算自己的尺寸
    [self sizeToFit];
}- (void)setImage:(UIImage *)image forState:(UIControlState)state
{[super setImage:image forState:state];// 只要修改了图片,就让按钮重新计算自己的尺寸
    [self sizeToFit];
}
@end

#import <UIKit/UIKit.h>@interface HWTitleButton : UIButton@end

HWStatus.h

#import <Foundation/Foundation.h>
@class HWUser;@interface HWStatus : NSObject
/**    string    字符串型的微博ID*/
@property (nonatomic, copy) NSString *idstr;/**    string    微博信息内容*/
@property (nonatomic, copy) NSString *text;/**    object    微博作者的用户信息字段 详细*/
@property (nonatomic, strong) HWUser *user;
@end

HWStatus.m

#import "HWStatus.h"@implementation HWStatus
@end

转载于:https://www.cnblogs.com/ios-g/p/4828212.html

IOS第四天-新浪微博 -存储优化OAuth授权账号信息,下拉刷新,字典转模型相关推荐

  1. 优化小程序中频繁下拉刷新导致的定位获取失败问题

    getLocation() {return new Promise((resolve, reject) => {let that =thiswx.getLocation({type: " ...

  2. ios html下拉刷新,Lottie_ios 实现下拉刷新

    一. Lottie 是什么 首先这个库是做什么的? 通过 AE 上的 Bodymovin 插件将 AE 中制作好的动画导出成一个 json 文件,Lottie 实现了 Android/iOS/Reac ...

  3. uni-app 小程序项目三 1. 商品列表、过滤器、封装商品item组件、上拉加载、节流阀、下拉刷新、2. 商品详情、轮播图、商品价格闪烁问题 3.加入购物车、vuex、持久化存储、mixiins

    1.0 创建 goodslist 分支 1.1 定义请求参数对象 为了方便发起请求获取商品列表的数据,我们要根据接口的要求,事先定义一个请求参数对象: data() {return {// 请求参数对 ...

  4. Android Compose 新闻App(四)下拉刷新、复杂数据、网格布局、文字样式

    Compose 新闻App(四)下拉刷新.复杂数据.网格布局.文字样式 前言 正文 一.下拉刷新 ① 添加依赖 ② 使用 ③ 样式更改 二.刷新数据 三.复杂数据 四.复杂列表 ① 更改返回数据 ② ...

  5. Android 天气APP(十)继续优化、下拉刷新页面天气数据

    上一篇:Android 天气APP(九)细节优化.必应每日一图 修复每日一图,增加下拉刷新,滑动改变标题 新版------------------- 一.修复每日请求必应壁纸Bug 二.增加下拉刷新 ...

  6. iOS 类似亲宝宝app下拉刷新动画效果

    iOS 类似亲宝宝app下拉刷新动画效果,最近看了下这种效果,感觉有点意思.于是就实现了一下. 方案一 采用两个背景View1.View2,三个球ball1,ball2,ball3,将ball1,ba ...

  7. 高仿IOS下拉刷新的粘虫效果

    最近看需要做一款下拉刷新的效果,由于需要和Ios界面保持一致,所以这用安卓的方式实现了ios下的下拉刷新的粘虫效果. 最新的安卓手机版本的QQ也有这种类似的效果,就是拖动未读信息的那个红色圆圈,拖动近 ...

  8. ios微信小程序下拉刷新怎么配_[wx]微信小程序自定义下拉刷新

    需求: 在小程序内存在列表等形式的页面内增加下拉刷新功能,提高用户体验感,加强界面操作与交互性: 实现方法: 1.小程序提供的下拉刷新(无法自定义刷新动画) 在页面设置内开启下拉(单独页面设置): { ...

  9. Android自定义控制(五)仿新浪微博的下拉刷新

    网上有很多很有名的开源框架,这里就来拉拉PullToRefresh这个框架,也就是我们平时用的下拉刷新啦,当然你问我这个有什么用啊?别人已经写好了,这里主要是学习以及练习,练习的次数多了,一切就顺其自 ...

最新文章

  1. 自动驾驶软件工程之全局规划
  2. 基于ZooKeeper的Hadoop HA集群搭建
  3. 宜信开源|详解PaaS平台LAIN的功能和架构
  4. anaconda在ubuntu中安装后没有_你的大数据平台中病毒了!!!记一次HDP安装后中dr.who病毒并修复的过程...
  5. php mysql 写法_php 类的写法
  6. 揭秘人工智能(系列):人工智能带来的网络安全威胁
  7. 【英语学习】【WOTD】circadian 释义/词源/示例
  8. 抖音起诉腾讯垄断 要求停止封禁并索赔9000万元
  9. UIScrollView 手势缩放
  10. python之循环(增删)内使用list.remove()
  11. 录屏软件 Apowersoft(傲软录屏)
  12. 项目CSS基础样式模板
  13. vue 自动播放语音
  14. NTFS和FAT32的区别和转换
  15. 同花顺股票交易接口 正确用法
  16. 芯片漫游指南(1)-- UVM世界观
  17. Boosting方法详解
  18. 亚像素边缘提取的例子
  19. golang 调试工具dlv 各个命令的用法
  20. 推荐5款让你相见恨晚的神级软件,把把直击心灵

热门文章

  1. 0-1背包一维数组的执行过程图示
  2. HDU OJ Super Jumping! Jumping! Jumping!
  3. 看懂OpenCV中IplImage转换成CvMat的语句:CvMat sstub, *src = cvGetMat(srcarr, sstub);
  4. 如何让cxf客户端简单支持ssl
  5. centos rpm安装mysql5.5_CentOS 5.5下RPM方式安装MySQL 5.5 详解
  6. leetcode算法题--飞机座位分配概率
  7. access实验报告体会_Access实验报告 - 图文
  8. python批量分析表格_示例python 批量操作excel统计销售榜品牌及销售额
  9. Linux脚本选题背景,shell实例100例《一》
  10. springmvc 返回xml数据