Cell網(wǎng)絡(luò)請求數(shù)據(jù)的處理

這里總結(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
  • 有關(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ù)還沒到呢)
[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修飾的全局變量\常量
        1. 僅限于當(dāng)前文件訪問
        1. 改變了作用域
    • 2> 被static修飾的局部變量
        1. 只會占用一塊內(nèi)存阅酪,在整個程序運行過程都不會銷毀旨袒,只會初始化一次
        1. 改變了生命周期,并沒有改變作用域
    • 例如:static int const money = 30;
      • 當(dāng)前文件中你都可以訪問遮斥,其它文件不行
  • 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!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末几迄,一起剝皮案震驚了整個濱河市蔚龙,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌映胁,老刑警劉巖木羹,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異解孙,居然都是意外死亡坑填,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進店門弛姜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來脐瑰,“玉大人,你說我怎么就攤上這事娱据◎胶冢” “怎么了?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵中剩,是天一觀的道長忌穿。 經(jīng)常有香客問我,道長结啼,這世上最難降的妖魔是什么掠剑? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮郊愧,結(jié)果婚禮上朴译,老公的妹妹穿的比我還像新娘。我一直安慰自己属铁,他們只是感情好眠寿,可當(dāng)我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著焦蘑,像睡著了一般盯拱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上例嘱,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天狡逢,我揣著相機與錄音,去河邊找鬼拼卵。 笑死奢浑,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的腋腮。 我是一名探鬼主播雀彼,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼壤蚜,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了详羡?” 一聲冷哼從身側(cè)響起仍律,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤嘿悬,失蹤者是張志新(化名)和其女友劉穎实柠,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體善涨,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡窒盐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了钢拧。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蟹漓。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖源内,靈堂內(nèi)的尸體忽然破棺而出葡粒,到底是詐尸還是另有隱情,我是刑警寧澤膜钓,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布嗽交,位于F島的核電站,受9級特大地震影響颂斜,放射性物質(zhì)發(fā)生泄漏夫壁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一沃疮、第九天 我趴在偏房一處隱蔽的房頂上張望盒让。 院中可真熱鬧,春花似錦司蔬、人聲如沸邑茄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽肺缕。三九已至,卻和暖如春吨些,著一層夾襖步出監(jiān)牢的瞬間搓谆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工豪墅, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留泉手,地道東北人。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓偶器,卻偏偏與公主長得像斩萌,于是被迫代替她去往敵國和親缝裤。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,515評論 2 359

推薦閱讀更多精彩內(nèi)容

  • *面試心聲:其實這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結(jié)起來就是把...
    Dove_iOS閱讀 27,162評論 30 470
  • 國家電網(wǎng)公司企業(yè)標準(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報批稿:20170802 前言: 排版 ...
    庭說閱讀 11,005評論 6 13
  • iOS網(wǎng)絡(luò)架構(gòu)討論梳理整理中颊郎。憋飞。。 其實如果沒有APIManager這一層是沒法使用delegate的姆吭,畢竟多個單...
    yhtang閱讀 5,206評論 1 23
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫榛做、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,120評論 4 61
  • 本來是看了笑來老師的推薦内狸,說《奇特的一生》給了少年的他如何大的觸動检眯,令他徹底改變對時間的概念。既然是師父的師父昆淡,自...
    飛鳥逐溪閱讀 262評論 0 0