這里總結(jié)的是cell請求和返回數(shù)據(jù)許多細節(jié)方面的處理
項目地址:https://github.com/Tuberose621/Cell-
一
-
自定義cell
- 一般當(dāng)系統(tǒng)不能滿足我們的需求時节芥,就要自定義
- 發(fā)現(xiàn)cell固定头镊,大小相同的時候勾選Xib相艇,今后的cell從Xib中加載
- cell一般要到緩存池中取坛芽,緩存池中沒有就注冊,重新創(chuàng)建
- 注冊時Xib中要設(shè)置Identifier為:tag
- 勾選Xib的時候用registerNib
- 沒有的時候用registerClass
- Xib是固定的获讳,可以設(shè)置一個高度為70
- 注冊時Xib中要設(shè)置Identifier為:tag
- 有關(guān)于cell之間的分割線的設(shè)置
- 系統(tǒng)的滿足不了我們了要求太粗赔嚎,我們需要自定義分割線,一般有兩種方法
- 首先設(shè)置cell的的高结缚,去掉系統(tǒng)自帶的分割線
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title = @"推薦標簽";
self.view.backgroundColor = CYCommonBgColor;
// 設(shè)置行高
self.tableView.rowHeight = 70;
// 去掉系統(tǒng)自帶的分割線
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
}
- 然后再考慮怎么設(shè)置分割線
- 方法一:添加一個UIView(設(shè)置它的frame:距左红竭,右喘落,下為0 瘦棋。設(shè)定高為1赌朋,透明度為0.2)
- 但是這種方法帶來了許多的子控件,當(dāng)我們的cell較多的時候不推薦這種方法
- 方法二:保持cell的位置不變赡若,高度都減1
- 這樣就可以少許多的子控件
- 但是這樣又有一些細節(jié)和注意的地方逾冬。分析如下:
- 有人會想在下面的cellForRowAtIndexPath:方法中修改cell的frame
- 但是這是不可能的身腻。因為這里是返回indexPath位置對應(yīng)的cell霸株,你如果是在這里修改后,一旦return cell坡椒。
- 又會被TableView(系統(tǒng))重新計算IndexPath對應(yīng)cell的高度(前面你有有設(shè)定cell高度為70)倔叼,frame等
- 循環(huán)利用丈攒,又會被系統(tǒng)修改回去
- 所以別想著在這里修改cell的frame
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CYTagCell *cell = [tableView dequeueReusableCellWithIdentifier:@"tag"];
return cell;
}
- 也有人可能會想著實現(xiàn)代理方法巡验,在下面的didSelectRowAtIndexPath:方法中修改cell的高度显设,每選中一次就讓它的高度減1也可以實現(xiàn)分割線
- 但是:同樣的在上面的cellForRowAtIndexPath:方法中辛辨,用戶一做上拉操作斗搞,就會循環(huán)利用僻焚,cell的高又會被系統(tǒng)重新修改回去
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
CYTagCell *cell = (CYTagCell *)[tableView cellForRowAtIndexPath:indexPath];
cell.height -= 1;
}
- 所以存在的問題:自己手動修改了cell的frame后,很有可能會被系統(tǒng)改回去
- 那么解決的方案:在系統(tǒng)設(shè)置完cell的frame后澡屡,自己再手動修改cell的frame, 重寫setFrame:方法
- 重寫這個方法的目的:攔截cell的frame設(shè)置驶鹉,系統(tǒng)改完后室埋,我再改姚淆,永遠改在系統(tǒng)的后面
- 不用擔(dān)心高度會遞減,前面有設(shè)置cell的高度為70腌逢,在每次傳進cell高度減1前降淮,cell都會重新設(shè)置高度為原來的70
- (void)setFrame:(CGRect)frame
{
frame.size.height -= 1;
[super setFrame:frame];
}
- 重寫setFrame:方法引申出來的價值
- 1.當(dāng)我們今后要攔截系統(tǒng)的某些設(shè)置(frame,size等)搏讶,某些操作(像push)的時候佳鳖。我們就要想到是不是可以去重寫它們相應(yīng)的方法
- 2.今后如果我們自定義的控件有一些特殊的需求,不希望外界可以輕松修改我們內(nèi)部的值(像frame系吩,size等)《饰担或者是為了避免外界誤傳值修改了尺寸等值穿挨,我們就可以重寫setFrame:方法
- 當(dāng)然別也可以通過修改bounds來修改尺寸,你就還得重寫setBounds:方法肴盏,人家也還可以通過修改transform來修改科盛,你就還得重寫setTransform:方法。一般不會如此變態(tài)
- 只是說記得有這么個細節(jié)和問題叁鉴,知道可以這么干
- 設(shè)置左右間距
- x向右移動一個你定的間距margin土涝,然后width減2倍間距margin
- 就設(shè)置好了cell的分割線,以及左右間隔或者是左右間隔線
- (void)setFrame:(CGRect)frame
{
frame.size.height -= 1;
frame.origin.x = 5;
frame.size.width -= 2 * frame.origin.x;
[super setFrame:frame];
}
- 網(wǎng)絡(luò)請求真實的數(shù)據(jù)
- 首先幌墓,要注意的地方:
- 使用Xcode7進行數(shù)據(jù)請求時
- 蘋果新特性要求App內(nèi)訪問網(wǎng)絡(luò)請求,要采用 HTTPS 協(xié)議
- 但是現(xiàn)在公司的項目使用的是 HTTP 協(xié)議冀泻,使用私有加密方式保證數(shù)據(jù)安全〕B拢現(xiàn)在也不能馬上改成 HTTPS 協(xié)議傳輸。
- 解決辦法:
- 在Info.plist中添加 NSAppTransportSecurity 類型 Dictionary
- 在 NSAppTransportSecurity 下添加 NSAllowsArbitraryLoads 類型Boolean ,值設(shè)為 YES
- 方式一: 使用文本編輯Info.plist, 在當(dāng)中添加:
- 解決辦法:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
- 方式二: 在Info.plist中添加:
- 發(fā)送請求給服務(wù)器弹渔,獲取數(shù)據(jù)
- 加載標簽數(shù)據(jù)
- 使用AFNetworking框架
- 先要根據(jù)API文檔請求參數(shù)
- 參數(shù)是一個字典胳施,里面有各種參數(shù)
- 發(fā)送請求
// 加載標簽數(shù)據(jù)
// 請求參數(shù)
NSMutableDictionary *params = [NSMutableDictionary dictionary];
params[@"a"] = @"tag_recommend";
params[@"action"] = @"sub";
params[@"c"] = @"topic";
// 發(fā)送請求
[[AFHTTPSessionManager manager] GET:@"http://api.budejie.com/api/api_open.php" parameters:params success:^(NSURLSessionDataTask *task, id responseObject) {
// 將服務(wù)器的數(shù)據(jù)寫成plist。方便查看數(shù)據(jù)結(jié)構(gòu)
[responseObject writeToFile:@"/Users/gecongying/Desktop/tag.plist" atomically:YES];
} failure:^(NSURLSessionDataTask *task, NSError *error) {
}];
}
- 一般開發(fā)的適合你可以將服務(wù)器的數(shù)據(jù)寫成plist肢专。這樣方便查看數(shù)據(jù)結(jié)構(gòu)
可以看出plist文件中有許多的字典數(shù)組舞肆,所以我們要將字典轉(zhuǎn)模型
-
字典轉(zhuǎn)模型時焦辅,公司的服務(wù)器可能傳回來一堆的數(shù)組,但是真正用到可以用于顯示的數(shù)據(jù)只有幾個椿胯,沒必要每個都寫筷登,只取我需要的
- 像這里只需要用到“頭像”“訂閱數(shù)”“name”三個數(shù)據(jù)
字典數(shù)組轉(zhuǎn)模型數(shù)組。所以搞一個模型數(shù)組(新建標簽?zāi)P虲YTag)(方便開發(fā))哩盲,這里選用MJExtension框架
在CYTag.h文件中
#import <Foundation/Foundation.h>
@interface CYTag : NSObject
/** 圖片 */
@property (nonatomic, copy) NSString *image_list;
/** 訂閱數(shù) */
@property (nonatomic, assign) NSInteger sub_number;
// 這里用NSInteger是為了后面更好的處理數(shù)字
/** 名字 */
@property (nonatomic, copy) NSString *theme_name;
@end
- 在CYTagViewController.m文件中
- 用一個標簽數(shù)組保存標簽數(shù)據(jù)(里面放的是CYTag模型)
#import "CYTagViewController.h"
#import "CYTagCell.h"
#import <AFNetworking.h>
#import <MJExtension.h>
#import "CYTag.h"
@interface CYTagViewController ()
/** 所有的標簽數(shù)據(jù)(里面存放的都是CYTag模型) */
@property (nonatomic, strong) NSArray *tags;
@end
@implementation CYTagViewController
- 在TableView數(shù)據(jù)源方法中,cell返回的個數(shù)
#pragma mark - <UITableViewDataSource>
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.tags.count;
}
- 在CYTagCell.Xib文件中前方,將cell中的控件以及控件之間的束設(shè)置好。
- 要把模型數(shù)組顯示到cell對應(yīng)的位置廉油,所以得進行拖線,拖到CYTagcell.m文件中
@interface CYTagCell()
@property (weak, nonatomic) IBOutlet UIImageView *imageListView;
@property (weak, nonatomic) IBOutlet UILabel *themeNameLabel;
@property (weak, nonatomic) IBOutlet UILabel *subNumberLabel;
@end
- 字典轉(zhuǎn)模型
- 字典轉(zhuǎn)模型后要記得刷新表格
// 發(fā)送請求
[[AFHTTPSessionManager manager] GET:@"http://api.budejie.com/api/api_open.php" parameters:params success:^(NSURLSessionDataTask *task, id responseObject) {
// 將服務(wù)器的數(shù)據(jù)寫成plist惠险。方便查看數(shù)據(jù)結(jié)構(gòu)
// [responseObject writeToFile:@"/Users/gecongying/Desktop/tag.plist" atomically:YES];
// responseObject:字典數(shù)組
// self.tags:模型數(shù)組
// responseObject -> self.tags
// 字典數(shù)組轉(zhuǎn)模型數(shù)組
self.tags = [CYTag objectArrayWithKeyValuesArray:responseObject];
// 刷新表格
[self.tableView reloadData];
} failure:^(NSURLSessionDataTask *task, NSError *error) {
}];
}
- CYTagCell內(nèi)部要拿到相應(yīng)的數(shù)據(jù),所以也需要有標簽?zāi)P?
- 下面的命名之所以用tagModel而不用tag
- 因為系統(tǒng)控件基本都有tag屬性抒线,取名不正確會被系統(tǒng)覆蓋
- 所以有時候取名也得注意
@classCYTag;
@interface CYTagCell : UITableViewCell
/** 標簽?zāi)P?*/
@property (nonatomic, strong) CYTag *tagModel;
- setTagModel
- (void)setTagModel:(CYTag *)tagModel
{
_tagModel = tagModel;
self.themeNameLabel.text = tagModel.theme_name;
self.subNumberLabel.text = tagModel.sub_number;
- 字典轉(zhuǎn)模型班巩,基本就以下三行代碼:
/**
* 返回indexPath位置對應(yīng)的cell
*/
-(UITableViewCell *)tableView: (UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath
{
CYTagCell *cell = [tableView dequeueReusableCellWithIdentifier:@"tag"];
cell.tagModel = self.tags[indexPath.row];
return cell;
}
- 現(xiàn)在只剩下圖片的下載
- 以及顯示下載的圖片,名字嘶炭,以及訂閱數(shù)
- 在CYTagCell.m文件中用SDWebImage框架下載和顯示圖片
- 顯示標題
- 訂閱數(shù)-有關(guān)于數(shù)字的處理
- 大于一萬(tagModel.sub_number / 10000.0)與不到一萬的處理
- %.1f萬人訂閱--多少萬人訂閱趣竣,并保留1位小數(shù)
- (void)setTagModel:(CYTag *)tagModel
{
_tagModel = tagModel;
// 下載頭像(SDWebImage框架給了一個占位圖片defaultUserIcon)
[self.imageListView sd_setImageWithURL:[NSURL URLWithString:tagModel.image_list] placeholderImage:[UIImage imageNamed:@"defaultUserIcon"]];
self.themeNameLabel.text = tagModel.theme_name;
// tagModel.sub_number = 678;
// 訂閱數(shù)
// 有關(guān)于數(shù)字的處理
if (tagModel.sub_number >= 10000) {
self.subNumberLabel.text = [NSString stringWithFormat:@"%.1f萬人訂閱", tagModel.sub_number / 10000.0];
} else {
self.subNumberLabel.text = [NSString stringWithFormat:@"%zd人訂閱", tagModel.sub_number];
}
}
- 關(guān)于訂閱數(shù)顯示,可以加tagModel.sub_number = 678這句代碼旱物,用這樣的假數(shù)據(jù)測試一下
- 顯示結(jié)果:
細節(jié)處理部分
用戶網(wǎng)速慢的時候遥缕,網(wǎng)絡(luò)有延遲的時候
- 用戶網(wǎng)速慢,網(wǎng)絡(luò)有延遲的時候宵呛。會出現(xiàn)跳轉(zhuǎn)后单匣,沒有內(nèi)容,空白一片
- 下面模擬一下網(wǎng)速慢的時候出現(xiàn)的上述情況
// 發(fā)送請求
[[AFHTTPSessionManager manager] GET:@"http://api.budejie.com/api/api_open.php" parameters:params success:^(NSURLSessionDataTask *task, id responseObject) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 *NSEC_PER_SEC)), dispatch_get_main_queue(),^{
self.tags = [CYTag objectArrayWithKeyValuesArray:responseObject];
[self.tableView reloadData];
});
- 用SVProgressHUD框架
- 在數(shù)據(jù)加載請求前先彈一個框宝穗,數(shù)據(jù)請求成功后再隱藏掉
- 這里是為了用戶體驗更好(網(wǎng)絡(luò)慢户秤,人家一進來就是一片空白什么鬼)
- 也為了防止用戶在數(shù)據(jù)請求前做操作或是直接點擊離開界面(數(shù)據(jù)還沒到呢)
- 在數(shù)據(jù)加載請求前先彈一個框宝穗,數(shù)據(jù)請求成功后再隱藏掉
[SVProgressHUD showWithMaskType:SVProgressHUDMaskTypeBlack];
- 數(shù)據(jù)回來后關(guān)閉彈框
[SVProgressHUD dismiss];
-
為了嚴謹期間,數(shù)據(jù)加載失敗情況下逮矛,也要彈框
- 1.服務(wù)器出現(xiàn)問題鸡号,返回數(shù)據(jù)為空
- 2.請求路徑出錯
# pragma mark- 專門加載標簽數(shù)據(jù)
- (void)loadTags
{
// 彈框
// [SVProgressHUD showWithMaskType:SVProgressHUDMaskTypeBlack];
[SVProgressHUD show];
// 請求參數(shù)
NSMutableDictionary *params = [NSMutableDictionary dictionary];
params[@"a"] = @"tag_recommend";
params[@"action"] = @"sub";
params[@"c"] = @"topic";
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// 發(fā)送請求
[[AFHTTPSessionManager manager] GET:@"http://api.budejie.com/api/api_open.php" parameters:params success:^(NSURLSessionDataTask *task, id responseObject) {
if (responseObject == nil) {
// 關(guān)閉彈框
[SVProgressHUD showErrorWithStatus:@"加載標簽數(shù)據(jù)失敗"];
return;
}
self.tags = [CYTag objectArrayWithKeyValuesArray:responseObject];
// 刷新表格
[self.tableView reloadData];
// 關(guān)閉彈框
[SVProgressHUD dismiss];
} failure:^(NSURLSessionDataTask *task, NSError *error) {
// 關(guān)閉彈框
[SVProgressHUD showErrorWithStatus:@"加載標簽數(shù)據(jù)失敗"];
}];
});
}
- 今后遇上此種網(wǎng)絡(luò)請求問題,一定記得給用戶彈框啊
- 但是這樣處理了還有隱患
- 隱患一:假如數(shù)據(jù)請求不到的時候须鼎,你就會一直在那兒彈框
- 隱患二:用戶仍然可以點擊上面的返回鍵鲸伴,但是到了上一個界面,你還是在彈框
- 這又要怎么辦呢晋控?用戶體驗不行啊
- 方法一:在dealloc:方法中dismiss一下
- (void)dealloc
{
[SVProgressHUD dismiss];
}
- 方法二:在控制器即將消失前dismiss掉(此法較為霸道)
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[SVProgressHUD dismiss];
}
-
在實際開發(fā)中遇上的問題
- 也是AFN框架自己的小問題
- 用AFN框架的block時建議使用弱引用weakSelf
# pragma mark- 專門加載標簽數(shù)據(jù)
- (void)loadTags
{
// 彈框
// [SVProgressHUD showWithMaskType:SVProgressHUDMaskTypeBlack];
[SVProgressHUD show];
// 加載標簽數(shù)據(jù)
// 請求參數(shù)
NSMutableDictionary *params = [NSMutableDictionary dictionary];
params[@"a"] = @"tag_recommend";
params[@"action"] = @"sub";
params[@"c"] = @"topic";
// 發(fā)送請求
__weak typeof(self) weakSelf = self;
[self.manager GET:@"http://api.budejie.com/api/api_open.php" parameters:params success:^(NSURLSessionDataTask *task, id responseObject) {
if (responseObject == nil) {
// 關(guān)閉彈框
[SVProgressHUD showErrorWithStatus:@"加載標簽數(shù)據(jù)失敗"];
return;
}
// responseObject:字典數(shù)組
// weakSelf.tags:模型數(shù)組
// responseObject -> weakSelf.tags
weakSelf.tags = [CYTag objectArrayWithKeyValuesArray:responseObject];
// 刷新表格
[weakSelf.tableView reloadData];
// 關(guān)閉彈框
[SVProgressHUD dismiss];
} failure:^(NSURLSessionDataTask *task, NSError *error) {
// 關(guān)閉彈框
[SVProgressHUD showErrorWithStatus:@"加載標簽數(shù)據(jù)失敗"];
}
}];
}
-
分析要用弱引用self的原因
- 因為用了self汞窗,成功success的block對我們self的控制器有一個強引用(這是因為manager有字典,它強引用著block赡译。只要manager不死予弧,block就不會死)這樣的話控制器是不死的
- 只有block死领舰,self才會死丑慎,控制器也就才會死--這個時候沒有block強指針指著它了
- 而block只有請求完畢,調(diào)用完block后誓斥,那些代理方法刪除后才會死(在didCompleteWithError:(請求完畢)方法中有一句:removeDelegateForTask)只有在這個時候,移除了一些代理方法后许帐,block才會死
- 那么控制器只有在服務(wù)器那兒請求完畢后才會銷毀(也就是網(wǎng)絡(luò)慢的時候的情況
- 所以用弱引用self
- 這樣意味著劳坑,不管block死不死,我的控制器都不會被強引用著
-
網(wǎng)絡(luò)請求仍有細節(jié)問題
- 當(dāng)發(fā)送請求時舞吭,網(wǎng)速慢泡垃,用戶點擊返回后,雖然控制器掛了羡鸥,但是AFN內(nèi)部仍然在請求網(wǎng)絡(luò)數(shù)據(jù)蔑穴,在浪費用戶的流量
- 所以要在控制器掛掉前,停止請求數(shù)據(jù)
-
AFN請求數(shù)據(jù)主要由manager惧浴,所以要給manager設(shè)個屬性存和,不管強弱(AFN內(nèi)部早就封裝存儲好了,但最好是弱引用)
- 一般框架內(nèi)部的東西衷旅,我們最好用弱引用好些
- 然后進行懶加載
/** 請求管理者 */
@property (nonatomic, weak) AFHTTPSessionManager *manager;
@end
@implementation CYTagViewController
- (AFHTTPSessionManager *)manager
{
if (!_manager) {
_manager = [AFHTTPSessionManager manager];
}
return _manager;
}
- 在dealloc:方法中捐腿,AFN內(nèi)部有方法,讓所有對象執(zhí)行cancel方法柿顶,停止請求
- 今后要管理AFN的所有任務(wù)茄袖,只要拿到manager就行了
- 細節(jié)問題
- 判斷是取消任務(wù)(code = -999)還是返回數(shù)據(jù)(域名,服務(wù)器嘁锯,URL等)
# pragma mark- 專門加載標簽數(shù)據(jù)
- (void)loadTags
{
// 彈框
// [SVProgressHUD showWithMaskType:SVProgressHUDMaskTypeBlack];
[SVProgressHUD show];
// 加載標簽數(shù)據(jù)
// 請求參數(shù)
NSMutableDictionary *params = [NSMutableDictionary dictionary];
params[@"a"] = @"tag_recommend";
params[@"action"] = @"sub";
params[@"c"] = @"topic";
// 發(fā)送請求
__weak typeof(self) weakSelf = self;
[self.manager GET:@"http://api.budejie.com/api/api_open.php" parameters:params success:^(NSURLSessionDataTask *task, id responseObject) {
if (responseObject == nil) {
// 關(guān)閉彈框
[SVProgressHUD showErrorWithStatus:@"加載標簽數(shù)據(jù)失敗"];
return;
}
// responseObject:字典數(shù)組
// weakSelf.tags:模型數(shù)組
// responseObject -> weakSelf.tags
weakSelf.tags = [CYTag objectArrayWithKeyValuesArray:responseObject];
// 刷新表格
[weakSelf.tableView reloadData];
// 關(guān)閉彈框
[SVProgressHUD dismiss];
} failure:^(NSURLSessionDataTask *task, NSError *error) {
// 如果是取消了任務(wù)宪祥,就不算請求失敗,就直接返回
if (error.code == NSURLErrorCancelled) return;
if (error.code == NSURLErrorTimedOut) {
// 關(guān)閉彈框
[SVProgressHUD showErrorWithStatus:@"加載標簽數(shù)據(jù)超時家乘,請稍后再試蝗羊!"];
} else {
// 關(guān)閉彈框
[SVProgressHUD showErrorWithStatus:@"加載標簽數(shù)據(jù)失敗"];
}
}];
}
- (void)dealloc
{
// 停止請求
[self.manager invalidateSessionCancelingTasks:YES];
// [self.manager.downloadTasks makeObjectsPerformSelector:@selector(cancel)];
// [self.manager.dataTasks makeObjectsPerformSelector:@selector(cancel)];
// [self.manager.uploadTasks makeObjectsPerformSelector:@selector(cancel)];
// [self.manager.tasks makeObjectsPerformSelector:@selector(cancel)];
// for (NSURLSessionTask *task in self.manager.tasks) {
// [task cancel];
// }
[SVProgressHUD dismiss];
}
-
網(wǎng)絡(luò)請求幾個細節(jié)總結(jié)
- 1.block里面不用self,用Weakself
- 2.將manager存起來仁锯,方便管理任務(wù)Tasks請求
- 3.有時候服務(wù)器返回的數(shù)據(jù)是空的耀找,嚴謹起見,彈框提示并return(情況一般少見)
- 4.在Failure這個block中做事情的時候业崖,一定要分清楚情況:是取消任務(wù)還是別的原因來到Failure的
- 5.控制器掛掉時野芒,一定要將請求關(guān)閉,不要浪費用戶的流量腻要,并且彈框提示關(guān)閉
設(shè)置圓角圖片
- 方法一
- 用CALayer設(shè)置圓角圖片复罐,但是會出現(xiàn)卡屏現(xiàn)象
- 蘋果在渲染的時候做了許多耗時耗能的內(nèi)部操作
- 不推薦使用
- (void)awakeFromNib
{
// 如果使用過于頻繁,可能會導(dǎo)致拖拽起來的感覺比較卡
self.imageListView.layer.cornerRadius = self.imageListView.width * 0.5;
self.imageListView.layer.masksToBounds = YES;
}
- 方法二
- 運用Quarz2D技術(shù)雄家,將圓角圖片畫上去
- if (image == nil) return;
- 這句代碼很有意義,如果沒有返回數(shù)據(jù),給一個占位圖片
- (void)setTagModel:(CYTag *)tagModel
{
_tagModel = tagModel;
CYWeakSelf;
// 下載頭像(SDWebImage框架給力一個占位圖片defaultUserIcon)
[self.imageListView sd_setImageWithURL:[NSURL URLWithString:tagModel.image_list] placeholderImage:[UIImage imageNamed:@"defaultUserIcon"] completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
// 如果圖片下載失敗趟济,就不做任何處理乱投,按照默認的做法:顯示占位圖片
// 下面這句代碼的意義是很大的
if (image == nil) return;
// 開啟圖形上下文
UIGraphicsBeginImageContext(image.size);
// 獲得上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 矩形框
CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height);
// 添加一個圓
CGContextAddEllipseInRect(ctx, rect);
// 裁剪(裁剪成剛才添加的圖形形狀)
CGContextClip(ctx);
// 往圓上面畫一張圖片
[image drawInRect:rect];
// 獲得上下文中的圖片
self.imageListView.image = UIGraphicsGetImageFromCurrentImageContext();
// 關(guān)閉圖形上下文
UIGraphicsEndImageContext();
}];
self.themeNameLabel.text = tagModel.theme_name;
// 訂閱數(shù)
// 有關(guān)于數(shù)字的處理
if (tagModel.sub_number >= 10000) {
self.subNumberLabel.text = [NSString stringWithFormat:@"%.1f萬人訂閱", tagModel.sub_number / 10000.0];
} else {
self.subNumberLabel.text = [NSString stringWithFormat:@"%zd人訂閱", tagModel.sub_number];
}
}
-
封裝一個UIImage的分類
- 在UIImage+CYExtension.h文件中
#import <UIKit/UIKit.h>
@interface UIImage (CYExtension)
/**
* 返回一張圓形圖片
*/
- (instancetype)circleImage;
/**
* 返回一張圓形圖片
*/
+ (instancetype)circleImageNamed:(NSString *)name;
@end
- 在UIImage+CYExtension.m文件中
#import "UIImage+CYExtension.h"
@implementation UIImage (CYExtension)
- (instancetype)circleImage
{
// 開啟圖形上下文
UIGraphicsBeginImageContext(self.size);
// 獲得上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 矩形框
CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);
// 添加一個圓
CGContextAddEllipseInRect(ctx, rect);
// 裁剪(裁剪成剛才添加的圖形形狀)
CGContextClip(ctx);
// 往圓上面畫一張圖片
[self drawInRect:rect];
// 獲得上下文中的圖片
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
// 關(guān)閉圖形上下文
UIGraphicsEndImageContext();
return image;
}
+ (instancetype)circleImageNamed:(NSString *)name
{
return [[self imageNamed:name] circleImage];
}
@end
-
封裝一個UIImageView設(shè)置頭像的分類
- 在UIImageView+CYExtension.h文件中
#import <UIKit/UIKit.h>
@interface UIImageView (CYExtension)
/**
* 設(shè)置頭像
*/
- (void)setHeader:(NSString *)url;
@end
- 在UIImageView+CYExtension.m文件中
#import "UIImageView+CYExtension.h"
#import <UIImageView+WebCache.h>
@implementation UIImageView (CYExtension)
- (void)setHeader:(NSString *)url
{
[self setCircleHeader:url];
}
- (void)setRectHeader:(NSString *)url
{
[self sd_setImageWithURL:[NSURL URLWithString:url] placeholderImage:[UIImage imageNamed:@"defaultUserIcon"]];
}
- (void)setCircleHeader:(NSString *)url
{
CYWeakSelf;
// PCH文件中有定義
UIImage *placeholder = [[UIImage imageNamed:@"defaultUserIcon"] circleImage];
[self sd_setImageWithURL:[NSURL URLWithString:url] placeholderImage:placeholder completed:
^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
// 如果圖片下載失敗,就不做任何處理顷编,按照默認的做法:會顯示占位圖片
if (image == nil) return;
weakSelf.image = [image circleImage];
}];
}
@end
- 今后不管你是要設(shè)置圓角還是直角的頭像
- 只需要一行代碼setCircleHeader:url或者是setRectHeader:url就行了
- (void)setHeader:(NSString *)url
{
[self setCircleHeader:url]; // 只需要改這里了哦
}
- 例如:
- (void)viewDidLoad {
[super viewDidLoad];
UIImageView *imageView = [[UIImageView alloc] init];
imageView.frame = CGRectMake(100, 100, 100, 100);
[imageView setHeader:@"https://www.baidu.com/img/bd_logo1.png"];
[self.view addSubview:imageView];
}
- 額外補充
- 1.cocoapods中的框架安裝中platform :ios, '6.0'
platform :ios, '6.0'
pod 'AFNetworking'~> 0.8'
這里寫7.0戚炫,寫8.0是有區(qū)別的
這是表明你下載的AFNetworking框架只支持iOS6的
如果有些功能只能在iOS7或者是iOS8中才有的,你是用不了的
如果想用最新版的一些功能就改為高版本的iOS8.0
-
2.DEBUG中宏定義的問題
- 這里可以創(chuàng)建一個宏媳纬,但是規(guī)定不能全是小寫双肤。如:age = 20;是不可以的
- aGe = 20 / age8 = 20這樣是可以的
- 3.有關(guān)于weak的問題
+ 一個對象死不死主要是看它有沒有強指針指著
- 4.IBOutlet的問題
- IBOutlet內(nèi)部有一個隱藏的強引用钮惠,它是由特殊用途的
- 它的內(nèi)部有強引用茅糜,為了在死之前做某些操作,具體在哪里不清楚素挽,但是不會影響使用蔑赘,我們能夠知道這個現(xiàn)象就可以了。weak的指針是會消失的预明,但IBOutlet內(nèi)部有一個強引用引用著缩赛,但是系統(tǒng)會在恰當(dāng)?shù)臅r候會將它去掉,不會影響weak的死亡時間撰糠。只是前后會有點差別酥馍,了解一下就好
- 所以自定義 IBOutlet 控件屬性一般也使用 weak
- 有關(guān)于全局變量使用
- 默認情況下,全局變量是全世界都可以訪問的
- 全局常量的寫法
- 1.僅限于本文件訪問
- 在本文件(.m)中寫下面的代碼
static 類型 const 常量名 = 常量值;
- 2.全世界都要訪問
- 1> 在CYConst.m文件中
#import <UIKit/UIKit.h>
類型 const 常量名 = 常量值;
// CYConst.m :定義所有的全局常量
#import <UIKit/UIKit.h>
// 請求路徑
NSString * const CYRequestURL = @"http://api.budejie.com/api/api_open.php";
- 2> 在CYConst.h文件中
#import <UIKit/UIKit.h>
UIKIT_EXTERN 類型 const 常量名;
// CYConst.h :引用所有的全局常量
#import <UIKit/UIKit.h>
// 請求路徑
UIKIT_EXTERN NSString * const CYRequestURL;
- 3> 在pch中包含CYConst.h文件
#import "CYConst.h"
-
static :
- 1> 被static修飾的全局變量\常量
- 僅限于當(dāng)前文件訪問
- 改變了作用域
- 2> 被static修飾的局部變量
- 只會占用一塊內(nèi)存阅酪,在整個程序運行過程都不會銷毀旨袒,只會初始化一次
- 改變了生命周期,并沒有改變作用域
- 例如:static int const money = 30;
- 當(dāng)前文件中你都可以訪問遮斥,其它文件不行
- 1> 被static修飾的全局變量\常量
- const :
- const只修飾它右邊的內(nèi)容峦失,被const修飾的內(nèi)容都是常量、都是不能再修改的
int * const p1; p1是常量术吗,*p1是變量
int const * p2; p2是變量尉辑,*p2是常量
const int * p3; p3是變量,*p3是常量
const int * const p4; p4是常量较屿,*p4是常量
int const * const p5; p5是常量隧魄,*p5是常量
- extern : 可以引用一個全局變量\常量
- 今后能用const就用const
- 只有一塊內(nèi)存,不能被修改
-
什么時候使用宏什么時候全局變量呢
- 在程序運行過程中隘蝎,未確定的那些值购啄,但是又可能經(jīng)常被用到,就用宏(例如前面定義了一個全局顏色)
- 而已經(jīng)完全確定嘱么,固定的狮含,全世界又要用的,就用const的全局變量
如果可以的話,Give me a star!