一、导航栏透明界面下移
self.extendedLayoutIncludesOpaqueBars = true
二、添加host域名
加快对应域名访问速度
1.sudo vim /etc/hosts
2.17.253.85.202 developer.apple.com
三、block未实现的闪退信息
https://www.jianshu.com/p/17d7c4714f0f
信息类似于
32位下的结果:EXC_BAD_ACCESS(code=1, address=0xc)异常
64位下的结果:EXC_BAD_ACCESS(code=1, address=0x10)异常
OC:使用block时,判断是否为空。
Swift:block定义为可选类型, 实现 block?()即可。
四、KVO
KVO本质是系统监测到某个属性的内存地址或常量改变时,
会添加上-(void)willChangeValueForKey:(NSString *)key和
-(void)didChangeValueForKey:(NSString *)key方法来发送通知。
五、GCD概念
http://www.qidiandasheng.com/2016/04/18/thread-deadlock/
任务和队列
任务:即操作,你想要干什么,说白了就是一段代码,在GCD中就是一个block。
同步(sync)和异步(async)的主要区别在于会不会阻塞当前线程,直到block中的任务执行完毕。
同步(sync)任务:它会阻塞当前线程并等待block中的任务执行完毕,然后当前线程才会继续往下执行,
当前前程是指任务1执行所在的线程,A线程里面有线程B,线程B执行任务1,不会影响线程A的任务的执行。
异步(async)任务:当前线程会直接往下执行,它不会阻塞当前线程,一般会开其他线程来执行任务。
队列:
用于存放任务,有串行队列和并行队列两种。
一、串行队列: FIFO(先进先出).
二、并行队列: 根据同步和异步有不同的执行方式。
同步:没有开启新的线程,串行执行任务。
异步:有开启新的线程,并行执行任务。
放到并行队列的任务,GCD也会FIFO的取出来,但不同的是,它取出来一个就会放到新开启的线程,
然后再取出来一个又放到另一个新开启的线程。由于取的动作很快,忽略不计,看起来,
所有的任务都是一起执行的。不过需要注意,GCD会根据系统资源控制并行的数量,所以任务很多,
它并不会让所有任务同时执行。
六、UIButton 设置title 和attributeText时的问题
attributeText 是优于title,所以设置再设置titile前设置attributeText 为nil
class MSFOrderUseBtn: UIButton {
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
var status: MSFOrderNoteStatus = .use {
didSet {
self.isHidden = false
self.setTitleColor(MSFColor.colorBlack23, for: .normal)
self.backgroundColor = MSFColor.colorYellowFFBF
self.titleLabel?.font = MSFFont.fontValue(size: 11, weight: .medium)
self.setTitle(nil, for: .normal)
self.setAttributedTitle(nil, for: .normal)
switch status {
case .use:
self.setTitle("去使用", for: .normal)
break
case .pubilshNote, .deleteNote:
self.setTitle("发布笔记", for: .normal)
break
case .modifyNote:
self.setTitle("修改笔记", for: .normal)
break
case .viewNote, .noteChecking:
self.setAttributedTitle(MSFHelper.underLineAttribute(text: "查看笔记", font: MSFFont.fontValue(size: 11, weight: .medium), range: NSRange(location: 0, length: 4), textColor: MSFColor.colorGray9B), for: .normal)
self.backgroundColor = .white
break
case .refund, .expired:
self.isHidden = true
break
default:
self.isHidden = true
break
}
}
}
}
七、监听WKWebView的ScrollView 的contentSize 更新 WKWebView高度出错
出现bug场景: A控件放上一个WKWebView(简称B)加载html,但是A高度根据B的contenSize的高度显示。
- (instancetype)init
{
self = [super init];
if (self) {
[self setupUI];
}
return self;
}
- (void)setupUI {
self.layer.masksToBounds = true;
self.backgroundColor = UIColor.whiteColor;
UILabel *label = [[UILabel alloc] init];
label.font = [UIFont systemFontOfSize:16 weight:UIFontWeightMedium];
label.textColor = [UIColor colorWithHex:0x222222];
label.text = @"详情描述";
[self addSubview:label];
[label mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self).mas_offset(15);
make.left.equalTo(self).mas_offset(15);
}];
_titleLabel = label;
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
_contentView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:config];
_contentView.navigationDelegate = self;
_contentView.scrollView.delegate = self;
_contentView.scrollView.scrollEnabled = false;
_contentView.scrollView.showsVerticalScrollIndicator = false;
_contentView.scrollView.showsHorizontalScrollIndicator = false;
[self addSubview:_contentView];
[_contentView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.equalTo(self);
make.top.equalTo(_titleLabel.mas_bottom).mas_offset(10);
make.height.mas_equalTo(0);
make.bottom.equalTo(self);
}];
#一、如果是masonry约束布局,请不要放在初始化的地方监听contentSize
[self.contentView.scrollView addObserver:self forKeyPath:@"contentSize" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:NULL];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
CGFloat new = [change[NSKeyValueChangeNewKey] CGSizeValue].height;
CGFloat old = [change[NSKeyValueChangeOldKey] CGSizeValue].height;
if (new != old) {
[self.contentView mas_updateConstraints:^(MASConstraintMaker *make) {
make.height.mas_equalTo(_contentView.scrollView.contentSize.height);
}];
}
}
- (void)setHtmlStr:(NSString *)htmlStr {
if (!htmlStr) return;
_htmlStr = htmlStr;
// NSLog(@"htmlStr: %@", htmlStr);
[_contentView loadHTMLString:htmlStr baseURL:nil];
#二、请放到这里监听contentSize
[self.contentView.scrollView addObserver:self forKeyPath:@"contentSize" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:NULL];
// [_contentView sizeToFit];
}
八、UICollectionViewCell上的gif图消失
出现场景: 外层CollectionView A reloadData时,A的cell上的CollectionView B 未reloadData,gif就会消失。
解决方案:A 刷新后,B也要刷新。
九、category
1、runtime初始化时,category的内存布局已经确定,没有ivar, 所以默认不能添加属性。
2、使用关联对象添加属性,重写setter和getter方法。
3、分类方法调用>原类的调用;保持原类方法调用,通过遍历方法列表,找到最后一个实现同名方法去执行即可。
如下: - (void)findClassMethod {
u_int count;
Method *methods = class_copyMethodList([Student class], &count);
NSInteger index = 0;
for (int i = 0; i < count; i++) {
SEL name = method_getName(methods[i]);
NSString *strName = [NSString stringWithCString:sel_getName(name) encoding:NSUTF8StringEncoding];
if ([strName isEqualToString:@"run"]) {
index = i; // 先获取原类方法在方法列表中的索引
}
}
// 调用方法
Student *stu = [[Student alloc] init];
SEL sel = method_getName(methods[index]);
IMP imp = method_getImplementation(methods[index]);
((void (*)(id, SEL))imp)(stu,sel);
}
4、objc_msgSend 遍历到方法,即停止遍历,而分类方法是在初始化是copy进方法列表。
5、原类有多个分类,原类load方法>A分类的load方法>B分类的load方法(A和B在buildPhase的顺序是A在前B在后)。但是A和B自定义同名的方法,只有B会执行,执行顺序是后进先出。所有B的同名方法先执行。
十、@synthesize 和 @dynamic
@proterty NSString *name;
@synthesize name = _name;
1.在.m文件重新定义成员变量名
2.当同时重写setter和getter方法是,下换线成员变量是无法直接使用的, 可使用@synthesize name = _name定义后,可以访问成员变量。
@dynamic: 系统不自动生成setter和getter方法,需要手动实现, 并且在.m文件定义成员变量。
{
NSString *_name;
}
十一、数据区域
常量区:用于存储常量数据,当整个应用程序结束后,其资源会由系统进行释放。
全局静态区:用来存储全局的静态数据,包括两个区域,存放未初始化的全局静态数据的区域被称为BSS区,存放已经初始化的全局静态数据的区域被称为数据区。
堆区:其内存的使用需要开发者手动申请,在MRC中其内存的释放也需要开发者自己进行管理。堆区的地址并不连续,并且会向高地址进行扩展,引用计数管理的就是这部分的内存。
栈区:由系统进行分配,通常用来存储函数参数、局部变量等数据。在实际开发中,指针变量本身存放在栈中,指向的对象数据会存放在堆中。存放地址更高。
十二、dispatch_group
本质:是个初始值为LONG_MAX的信号量,等待group中的任务完成其实是等待value、恢复初始值。
dispatch_group_enter和dispatch_group_leave必须成对出现。
dispatch_group_async的原理和dispatch_async比较类似,
区别在于group操作会带上DISPATCH_OBJ_GROUP_BIT标志位。
dispatch_group_async_f 与dispatch_async_f 主要执行以下操作:
1、调用dispatch_group_enter
2、将block和queue等信息记录到dispatch_continuation_t中,并将它加入到group的链表中。
3、_dispatch_continuation_pop执行时会判断任务是够为group。是的话执行完成任务再调用dispatch_group_leave以达到信号量value的平衡。
十三、结构体
结构体的地址:isa在内存中的地址就是结构体的地址,因为结构体的地址就是其中
第一个成员的地址。
内存对齐 结构体的大小必须是最大成员变量大小的整数倍。
#import <objc/runtime.h>
#import <malloc/malloc.h>
NSObject *obj = [[NSObject alloc] init];
printf("obj 成员变量实际大小: %zu", class_getInstanceSize([NSObject class]));
printf("obj 分配的大小: %zu", malloc_size((__bridge const void *)(obj)));
OC对象的本质是结构体。
一个obj实例是指向一个结构体的指针。
getInstanceSize 获取的是成员变量的大小(是内存对齐之后的大小)。
malloc是系统分配的内存大小,内存根据一个bucket的大小来分配内存, bucket的大小是16,32,48,所以系统是按16 的倍数来分配对象的内存大小的。
网友评论