项目实战No3 推荐标签

一 自定义cell–xib

  • cell分割线
    • 设置透明度可以使分割线变细
  • 自定义分割线
    • 方法一:去掉系统cell分割线,建一个高度为1的view当分割线;
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
  • 方法二:改变cell的高度-1,但是位置不变
    • 存在问题:手动修改完cell的frame,可能还会被系统改回去
    • 解决方案:在系统设置完cell的frame后,再手动修改cell的frame
/**
 * 重写这个方法的目的:拦截cell的frame设置
 */
- (void)setFrame:(CGRect)frame
{
    frame.size.height -= 1;
    // 设置左右加间距
    frame.origin.x += 5;
    [super setFrame:frame];
}

1.重写setFrame,控件frame永远不能修改
2.重写setBounds,控件bounds一样不能修改

二 显示标签数据

  • 加载标签数据
 // 加载标签数据
    // 请求参数
    NSMutableDictionary *params = [NSMutableDictionary dictionary];
    params[@"a"] = @"tag_recommend";
    params[@"action"] = @"sub";
    params[@"c"] = @"topic";
    // 发送请求
     // 发送请求
    [[AFHTTPSessionManager manager] GET:@"http://api.budejie.com/api/api_open.php" parameters:params success:^(NSURLSessionDataTask *task, id responseObject) {
    // 将服务器的数据写成plist。方便查看数据结构
// [responseObject writeToFile:@"/Users/lujing/Desktop/tag.plist" atomically:YES];

        // responseObject:字典数组
        // self.tags:模型数组
        // responseObject -> self.tags
        self.tags = [XMGTag objectArrayWithKeyValuesArray:responseObject];

        // 刷新表格
        [self.tableView reloadData];
    } failure:^(NSURLSessionDataTask *task, NSError *error) {

    }];
  • cell模型样式代码
    • 如果订阅数量比较大,显示x.xx万
#import <UIImageView+WebCache.h>
- (void)setTagModel:(XMGTag *)tagModel
{
    _tagModel = tagModel;

    [self.imageListView sd_setImageWithURL:[NSURL URLWithString:tagModel.image_list] placeholderImage:[UIImage imageNamed:@"defaultUserIcon"]];
    self.themeNameLabel.text = tagModel.theme_name;

    // 订阅数
    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];
    }
}

三 请求细节处理

  • 代码模拟网络比较慢的情况,加载过程
    • SVProgressHUD.h第三方框架
  • 加载数据,弹窗
[SVProgressHUD show];
// 同样功能,如果没有返回请求,用户没法回到上一view
//    [SVProgressHUD showWithMaskType:SVProgressHUDMaskTypeBlack];
  • 2种情况下,会显示加载标签数据失败
    • 发送一个空的响应
    • 发送地址不正确
  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  // 发送请求
   [AFHTTPSessionManager manager] GET:@"http://api.budejie.com/api/api_open.php"parameters:params success:^(NSURLSessionDataTask *task, id responseObject) {
        if (responseObject == nil) {
            // 关闭弹框
            [SVProgressHUD showErrorWithStatus:@"加载标签数据失败"];
            return;
        }
        // responseObject:字典数组
        // weakSelf.tags:模型数组
        // responseObject -> weakSelf.tags
       self.tags = [XMGTag objectArrayWithKeyValuesArray:responseObject];
        // 刷新表格
        [weakSelf.tableView reloadData];
        // 关闭弹框
        [SVProgressHUD dismiss];
    } failure:^(NSURLSessionDataTask *task, NSError *error) {
        // 如果是取消了任务,就不算请求失败,就直接返回
        if (error.code == NSURLErrorCancelled) return;

        if (error.code == NSURLErrorTimedOut) {
            // 关闭弹框
            [SVProgressHUD showErrorWithStatus:@"加载标签数据超时,请稍后再试!"];
        } else {
            // 关闭弹框
            [SVProgressHUD showErrorWithStatus:@"加载标签数据失败"];
        }
    }];
  • 加载数据弹窗用[SVProgressHUD show]时,返回弹窗仍存在
    • 方法1:控制器挂掉时,弹窗消失
- (void)dealloc
{
   [SVProgressHUD dismiss];
}
  • 方法2:view即将消失时,弹窗消失
- (void)viewWillDisappear:(BOOL)animated
{
   [super viewWillDisappear:animated];
   [SVProgressHUD dismiss];
}
  • block中使用self需要使用弱引用
  1. block交由manager管理,manager内部有字典组成,manager不死,block就不会死,由于block对self有一强引用,所以self也不会死
  2. block什么时候死?当请求完毕,调用完block时
  3. 原始需求实现点击返回,弹窗消失,__weak typeof(self) weakSelf = self;
  • 控制器关掉,需要停止请求

    • 方法1:数组所有任务执行cancel方法,相当于for循环

      [self.manager.tasks makeObjectsPerformSelector:@selector(cancel)];
    • 方法2:调用get方法,多个任务的话使用不方便

      /** 任务 */
      @property (nonatomic, weak) NSURLSessionTask *task;
      
      [self.task cancel];
    • 方法3 :所有任务取消掉

      [self.manager invalidateSessionCancelingTasks:YES];
  • 方法1和3区别

    • 方法1manager还可以用,相当于加载tasks时把之前请求取消,在发送一个新的请求;
    • 方法3把整个manager中session都干掉,在启用只能把manager清掉,在创建一个新的
  • 通过error判断请求是取消导致失败还是真的请求失败

    • NSURLErrorCancelled,error有一个code属性
      • kCFURLErrorCancelled = -999, 取消
      • kCFURLErrorTimedOut = -1001, 超时
      • kCFURLErrorUnsupportedURL = -1002, URL有误
      • kCFURLErrorCannotFindHost = -1003, 找不带服务器
      • kCFURLErrorCannotConnectToHost = -1004,

总结
1>block里面不写self;
2>建议把manager存起来,方便管理所有请求;
3>如果服务器返回对象是空的,增加判断处理
4>failure的block做事情时,判断是取消任务还是真的有错误
5>控制器挂掉一定要取消请求

弱指针注意点:属性只要加了IBOutlet,系统会有隐藏的强引用引用着对象;
只要是弱指针,最终都会死掉,死的时刻不一样;

四 圆角图片

  • 方法1:layer图层,如果使用过于频繁,会导致拖拽起来的感觉比较卡
- (void)awakeFromNib
{
     self.imageListView.layer.cornerRadius = self.imageListView.width * 0.5;
     self.imageListView.layer.masksToBounds = YES;
}
  • 方法2:裁剪
- (void)setTagModel:(XMGTag *)tagModel
{
    _tagModel = tagModel;

    UIImage *placeholder = [[UIImage imageNamed:@"defaultUserIcon"] circleImage];
    [self.imageListView sd_setImageWithURL:[NSURL URLWithString:tagModel.image_list] placeholderImage:placeholder 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);

    // 往圆上面画一张图片
    [self drawInRect:rect];

    // 获得上下文中的图片
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

    // 关闭图形上下文
    UIGraphicsEndImageContext();
   }];
}
  • 封装一个图片裁圆的分类 “UIImage+XMGExtension.h”
/**
 * 返回一张圆形图片
 */
- (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();

    // 关闭图形上下文
    UIGraphicsEndImageContext();

    return image;
}

+ (instancetype)circleImageNamed:(NSString *)name
{
    return [[self imageNamed:name] circleImage];
} 

五 封装圆角头像

  • 原始需求:项目中所有图片都可以裁剪成圆形
    • 新建分类 “UIImageView+XMGExtension.h”
- (void)setCircleHeader:(NSString *)url
{
    XMGWeakSelf;
    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];
   }];
}

六 全局常量和全局变量

  • 全局常量:宏,定义全局常量,不能修改,会产生很多临时空间;
  • 全局变量:可以修改,不会产生临时空间;
  • 折中办法:选择const

    • const : const只修饰它右边的内容,被const修饰的内容都是常量、都是不能再修改的;
    • static : 被static修饰的全局变量\常量
      • 1) 仅限于当前文件访问
      • 2) 改变了作用域
    • static : 被static修饰的局部变量

      • 1) 只会占用一块内存,在整个程序运行过程都不会销毁,只会初始化一次
      • 2) 改变了生命周期,并没有改变作用域
    • extern : 可以引用一个全局变量\常量(注意重复定义)

  • 增加全局常量方法

    • 仅限本文件中访问
      • 本文件(.m)中写代码:staic 类型 const 常量名 = 常量值;
    • 全世界都要访问
      • .h文件引用全局常量 : UIKIT_EXTERN 类型 const 常量名;
      • .m文件定义全局常量的值 : 类型 const 常量名 = 常量值;
    • 在pch中包含.h文件
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值