iOS 开发实训第十周周报
一、学习笔记
-
使用代码添加视图约束:
-
首先要保证相关控件都已经在各自的父控件上了,即要先
addSubview
,再addConstraint
添加约束 -
其次是不需要再给
view
设置frame
-
然后将
view
的translatesAutoresizingMaskIntoConstraints
属性设为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
引入,就会导致循环引用,编译时会报错,可以使用向前声明来解决
-
-
new
和alloc init
的区别:- 源码如下:
- 通过源码可以发现,
[className new]
基本等价于[[className alloc] init]
,区别只在于alloc
在分配内存时使用的是allocWithZone
方法,这个方法在给对象分配内存时会把关联的对象分配到一个相邻的内存区域内,加快调用时内存读取的速度,提升了程序的处理速度 - 另一个常用
alloc init
的原因是,我们可以定义多个initWithXXX
方法,可以接受不同的参数,使用更灵活
-
OC
中BOOL
、bool
和Boolean
对比: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
的图片,从而导致了滑动图片消失的效果 -
在属性中设置宽高
-
用约束设置宽高
-
-
在
block
内如何修改block
外的变量:- 默认情况下,在
block
中访问的外部变量都是复制过去的,所以在block
中修改不会对原变量产生影响,可以用__block
关键字修饰该变量使其在block
中可写 -
__block
关键字的底层实现原理:block
中不允许修改外部变量的值,这里所说的值指的是栈中指针的内存地址,__block
关键字的作用就是将外部变量在栈中的内存地址放到了堆中
- 默认情况下,在
-
如何在多个异步任务完成后执行某项操作:
-
在加载图片的时候发现,首先需要从接口获取一次列表,然后解析结果获取图片的
URL
,然后再去下载图片,每次加载列表都需要加载多个条目,所以需要多次下载图片的操作,然后因为使用NSURLSession
下载图片是在回调的Block
中获取到数据,所以每次加载列表都需要多个异步任务,并且需要等到这些异步任务都完成后才能将结果返回给view
-
解决方法:使用
dispatch_group_enter
、dispatch_group_leave
和dispatch_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); });
-
但是上面的代码只能保证这些异步任务完成,不能保证它们完成的顺序和开始的顺序一样
-
三、参考链接
- new和alloc init的区别
- 向前声明
- OC中BOOL bool Boolean的区别
- 使用代码添加约束
- 图片填充方式 contentMode
- __block关键字的底层实现原理
- 如何在外部获取回调block里的值
- 如何在多个异步任务完成后执行某项操作