*************applicationweb
- (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.mjson
// 帳號的存儲路徑 #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.mcanvas
#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.hapi
#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.建立一個webView UIWebView *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.得到url NSString *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:申請應用時分配的AppKey client_secret:申請應用時分配的AppSecret grant_type:使用authorization_code redirect_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.mapp
#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時間晚的微博),默認爲0 params[@"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.hide
#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的frame self.titleLabel.x = self.imageView.x; // 2.計算imageView的frame self.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.hui
#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.matom
#import "HWStatus.h" @implementation HWStatus @end