欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

iOS 开发实训第十周周报

程序员文章站 2022-04-11 13:19:06
...

一、学习笔记

  • 使用代码添加视图约束:

    • 首先要保证相关控件都已经在各自的父控件上了,即要先addSubview,再addConstraint添加约束

    • 其次是不需要再给view设置frame

    • 然后将viewtranslatesAutoresizingMaskIntoConstraints属性设为NO,表示禁用autoresizing功能,避免和系统生成的自动伸缩的约束冲突

    • constraintWithItem方法:

      • 示例:

        // 添加高约束
        NSLayoutConstraint *picHeight = [NSLayoutConstraint constraintWithItem:_imageView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:70];
        [_imageView addConstraint:picHeight];
        
        // 添加宽约束
        NSLayoutConstraint *picWeight = [NSLayoutConstraint constraintWithItem:_imageView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:70];
        [_imageView addConstraint:picWeight];
        
        // 添加y方向约束
        NSLayoutConstraint *picTop = [NSLayoutConstraint constraintWithItem:_imageView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:_imageView.superview attribute:NSLayoutAttributeTop multiplier:1.0 constant:60];[self addConstraint:picTop];
        
        // 添加x方向约束
        NSLayoutConstraint *picVer = [NSLayoutConstraint constraintWithItem:_imageView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:_imageView.superview attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0];
        [self addConstraint:picVer];
        
      • 各参数的意义分别为:

        • constraintWithItem:约束对象
        • attribute:约束属性
        • relatedBy:依赖关系
        • toItem:依赖对象
        • attribute:依赖属性
        • multiplier:系数
        • constant:常量
    • constraintWithVisualFormat方法:

      • VFL (Visual Format Language)是苹果公司为了简化Autolayout的编码而推出的抽象语言

      • 示例:

        NSDictionary *metrics = @{@"m":@20, @"h":@50};
        NSDictionary *views = @{@"yelloView":yellowView};
        NSString *vfl = @"H:|-m-[yellowView(==h)]-m-|";
        NSArray *constraints = [NSLayoutConstraint constraintWithVisualFormat:vfl options:kNilOptions metrics:metrics view:views];
        [self.view addConstraints:constraints];
        

        该示例设置yellowView的宽度为50,离父视图两边的水平距离为20

      • metrics参数定义变量对应的常数值,views参数定义变量对应的实际控件名,如果整个VFL语言中的所有控件变量都是用原名写的,可以用宏定义views参数,如views:NSDictionaryOfVariableBindings(yellowView)

    • 其他第三方框架

  • 向前声明 forward declaring

    • .h文件使用@class引入其他类,在.m文件中再使用#import的方法,比如

      // A.h
      #import <Foundation/Foundation.h>
      
      @class B; // 向前声明
      
      @interface A : NSObject
      
      // 在A的.h文件中需要定义B的实例对象,但在.h文件中不需要知道B的具体内容
      @property (nonatomicm, strong) B *b;
      
      @end
      
      // A.m
      #import "B.h" 
      
    • 优点:

      • 将引入头文件的时间尽量延后,只在确定需要时才引入,减少编译时间
      • 能解决两个类互相引用的问题:比如A类中有一个B类属性,而B类中又有一个A类属性,这时候如果在.h文件中使用#import引入,就会导致循环引用,编译时会报错,可以使用向前声明来解决
  • newalloc init 的区别:

    • 源码如下:

    iOS 开发实训第十周周报

    • 通过源码可以发现,[className new] 基本等价于 [[className alloc] init],区别只在于alloc在分配内存时使用的是allocWithZone方法,这个方法在给对象分配内存时会把关联的对象分配到一个相邻的内存区域内,加快调用时内存读取的速度,提升了程序的处理速度
    • 另一个常用alloc init的原因是,我们可以定义多个initWithXXX方法,可以接受不同的参数,使用更灵活
  • OCBOOLboolBoolean对比:

    Name Typedef Header True Value False Value
    BOOL signed char objc.h YES NO
    bool _bool stdbool.h true false
    Boolean unsigned char MacTypes.h TRUE FALSE
  • ImageView图片填充模式contentMode:由系统定义的枚举类型,默认为UIViewContentModeScaleToFill

    contentMode 作用效果
    UIViewContentModeScaleToFill 根据视图的比例去拉伸图片内容
    UIViewContentModeScaleAspectFit 保持图片自身的纵横比例拉伸来适应视图的大小,小于视图的部分为透明
    UIViewContentModeScaleAspectFill 拉伸图片以填充整个视图,大于视图的部分会被裁剪掉
    UIViewContentModeRedraw 单视图的尺寸位置发生变化的时候调用 setNeedsDisplay 方法来重新显示
    UIViewContentModeCenter 保持图片原比例(即不拉伸图片)在视图中间显示图片内容,大于视图的部分会被裁剪掉,下面的类似
    UIViewContentModeTop 保持图片原比例在视图中间顶部显示
    UIViewContentModeBottom 保持图片原比例在视图中间底部显示
    UIViewContentModeLeft 保持图片原比例在视图中间左边显示
    UIViewContentModeRight 保持图片原比例在视图中间右边显示
    UIViewContentModeTopLeft 保持图片原比例在视图左上角显示
    UIViewContentModeTopRight 保持图片原比例在视图右上角显示
    UIViewContentModeBottomLeft 保持图片原比例在视图左下角显示
    UIViewContentModeBottomRight 保持图片原比例在视图右下角显示

二、遇到的问题及解决方法

  • 对于上周没有解决的UITableView中图片显示错误的问题:

    • 上周一直认为是图片的缓存问题,所以一直无法解释为什么在列表的底部还有两张图片,这也正是突破口,实际上图片没有缓存问题,也没有错位,是ImageView的布局问题,在xib中,我之前不知道能给控件的宽度和高度也添加约束,只是在右边的控件属性里设置了宽度和高度,导致这个ImageView变得很奇怪,高度变得很大,在设置了图片源后这张图片只占了整个ImageView的底部,在图片上面有一大片的空白,所以一个cell的图片实际上是在该cell的下方,刚好在下两个cell的图片的位置,然后从下到上每个cell是一种叠上去的感觉,所以导致上面cell看起来是没有图片的,而列表底部又多出来两张图片的效果,当滑动列表时,点击的cell会移到前面的cell的上方,所以就覆盖了上面的cell的图片,从而导致了滑动图片消失的效果

    • 在属性中设置宽高

      iOS 开发实训第十周周报

    • 用约束设置宽高

    iOS 开发实训第十周周报

  • block内如何修改block外的变量:

    • 默认情况下,在block中访问的外部变量都是复制过去的,所以在block中修改不会对原变量产生影响,可以用__block关键字修饰该变量使其在block中可写
    • __block关键字的底层实现原理:block中不允许修改外部变量的值,这里所说的值指的是栈中指针的内存地址,__block关键字的作用就是将外部变量在栈中的内存地址放到了堆中
  • 如何在多个异步任务完成后执行某项操作:

    • 在加载图片的时候发现,首先需要从接口获取一次列表,然后解析结果获取图片的URL,然后再去下载图片,每次加载列表都需要加载多个条目,所以需要多次下载图片的操作,然后因为使用NSURLSession下载图片是在回调的Block中获取到数据,所以每次加载列表都需要多个异步任务,并且需要等到这些异步任务都完成后才能将结果返回给view

    • 解决方法:使用dispatch_group_enterdispatch_group_leavedispatch_group_notify保证等到任务完成后再执行后续操作

      dispatch_group_t downloadTaskGroup = dispatch_group_create();
      for (int i = 0; i < 20; i++) {
      		// ...
      		
      		dispatch_group_enter(downloadTaskGroup);
          [self downloadImageWithURL:url index:i success:^(NSString * _Nonnull imagePath) {
          		NewsModel *news = [NewsModel initWithTitle:title imagePath:imagePath];
              [arr addObject:news];
              dispatch_group_leave(downloadTaskGroup);
          } failure:^(NSError * _Nonnull error) {
          		NSLog(@"请求失败 error:%@",error.description);
              dispatch_group_leave(downloadTaskGroup);
          }];
      }
      dispatch_group_notify(downloadTaskGroup, dispatch_get_main_queue(), ^{
      		NSLog(@"%@", @"完成");
          success(arr);
      });
      
    • 但是上面的代码只能保证这些异步任务完成,不能保证它们完成的顺序和开始的顺序一样


三、参考链接