保存工作和学习过程中使用,学习到的Demo
使用block作为方法的参数,实现界面反向传值。
使用NSBlockOperation和NSCache,实现tableViewcell里加载网络图片,并带有缓存功能(仿照SDWebImage的逻辑)。
对于UIView,即使是用init
方法创建实例,也会先调用initWithFrame:
方法,然后再调用init
方法。
- 将tableview的datasource单独抽取出来作为一个类,减少viewcontroller的代码量。
- cell的绘制方法使用block函数调用。
在分类中使用关联对象给类添加属性。
瀑布流的实现,自定义cell的垂直,水平间距,以及列数。
- (void)viewDidLoad {
[super viewDidLoad];
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:CellIdentifier];
SSJMasonryLayout *layout = (SSJMasonryLayout*)self.collectionView.collectionViewLayout;
layout.delegate = self;
//自定义列数,cell的水平距离,cell的垂直距离
layout.numberOfColumns = 4;
layout.itemHorizontalSpacing = 10;
layout.itemVerticalSpacing = 20;
}
#pragma mark- SSJMasonryLayoutDeleagte
- (CGFloat) collectionView:(UICollectionView*) collectionView
layout:(SSJMasonryLayout*) layout
heightForItemAtIndexPath:(NSIndexPath*) indexPath {
//提供cell的随机高度
CGFloat randomHeight = 100 + (arc4random() % 140);
return randomHeight;
}
用KVC和runtime改变私有属性。
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;//公共属性
@end
@interface Person()
@property (nonatomic, copy) NSString *job;//私有属性
@end
@implementation Person
{
NSString *_country;//私有成员变量
}
[person setValue:@"jack" forKey:@"name"];//公共属性
[person setValue:@"coder" forKey:@"job"];//私有属性
[person setValue:@"China" forKey:@"country"];//私有成员变量
NSLog(@"kvc改变成员变量的值:%@",person);//name:jack, job:coder, country:China
####3. 使用runtime修改私有属性以及私有成员变量
[self changeIvarOfObject:person withIvarName:@"_job" toValue:@"manager"];
[self changeIvarOfObject:person withIvarName:@"_country" toValue:@"America"];
NSLog(@"runtime 改变成员变量的值:%@",person);//name:Bob, job:manager, country:America
- (void)changeIvarOfObject:(id)object withIvarName:(NSString *)name toValue:(NSString *)value
{
Ivar ivar = class_getInstanceVariable([object class], [name UTF8String]);
object_setIvar(object, ivar, value);
}
自定义转场动画:将push显示为model:新建一个类继承UIStoryboardSegue
,然后重写perform
方法。
#import "CustomSegue.h"
@implementation CustomSegue
- (void)perform
{
UIViewController *fromVC = (UIViewController *)self.sourceViewController;
UIViewController *toVC = (UIViewController*)self.destinationViewController;
//获取第一个页面初始状态的frame
CGRect f = fromVC.view.frame;
CGRect originalSourceRect = fromVC.view.frame;
f.origin.y = f.size.height;
//令第二个页面在开始的时候位于屏幕底部
toVC.view.frame = f;
toVC.view.alpha = 0.0f;
[[fromVC.view superview] addSubview:toVC.view];
[UIView animateWithDuration:0.3 animations:^{
//令第二个页面的frame等于第一个页面初始状态的frame(满屏)
toVC.view.frame = originalSourceRect;
toVC.view.alpha = 1.0f;
} completion:^(BOOL finished) {
[toVC.view removeFromSuperview];
fromVC.view.alpha = 1.0f;
[fromVC.navigationController pushViewController:toVC animated:NO];
}];
}
用FBKVOController实现的mvvm的双向绑定。
//模拟网络请求
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//新请求下来一个model
self.model = [[SJModel alloc] init];
self.model.number = arc4random() % 100;;
//viewmodel监听model的改变
[self.KVOController observe:self.model keyPath:@"number" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial block:^(id _Nullable observer, id _Nonnull object, NSDictionary<NSString *,id> * _Nonnull change) {
NSLog(@"viewmodel监听到了model的改变后,立即改变自己被控制器监听的属性");
self.contentStr = [self convertNumber:self.model.number];
}];
});
- (instancetype)initWithViewModel:(SJViewModel *)viewModel
{
self = [super init];
if (self) {
self.viewModel = viewModel;
//view监听viewmodel的contentStr属性的改变,一旦改变,刷新自己
[self.KVOController observe:self.viewModel keyPath:@"contentStr" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial block:^(id _Nullable observer, id _Nonnull object, NSDictionary<NSString *,id> * _Nonnull change) {
NSLog(@"当view监听到了viewmodel的改变后,立即改变自己");
self.label.text = self.viewModel.contentStr;
}];
}
return self;
}
线程通信的几个例子:NSOperation,GCD,NSObject
介绍了GCD的API:dispatch_barrier,dispatch_wait,dispatch_group,dispatch_apply等
由xib生成的view默认会跟随父控件大小的变化而变化。如果不让二者有依赖性,需要设置view的autoresizingMask属性。
UIView *subview = [[NSBundle mainBundle] loadNibNamed:@"subview" owner:nil options:nil].firstObject;
//不让xib的view随着父控件的大小而变化
subview.autoresizingMask = UIViewAutoresizingNone;
block的底层分析
使用runtime交换方法(类方法,实例方法)
交换类方法:
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
SEL originalSelector = @selector(imageNamed:);
SEL swizzledSelector = @selector(sj_imageNamed:);
Method originalMethod = class_getClassMethod(self, originalSelector);
Method swizzledMethod = class_getClassMethod(self, swizzledSelector);
//交换实现
method_exchangeImplementations(originalMethod, swizzledMethod);
});
}
+ (UIImage *)sj_imageNamed:(NSString *)name
{
UIImage *image = [UIImage sj_imageNamed:name];
if (image) {
NSLog(@"图片加载成功");
} else {
NSLog(@"图片加载失败");
}
return image;
}
交换实例方法:
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class class = [self class];
SEL originalSelector = @selector(viewWillAppear:);
SEL swizzledSelector = @selector(sj_viewWillAppear:);
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
//交换实现
method_exchangeImplementations(originalMethod, swizzledMethod);
});
}
- (void)sj_viewWillAppear:(BOOL)animated {
[self sj_viewWillAppear:animated];
NSLog(@"viewWillAppear: %@", self);
}
使用runtime交换方法来同志array count是否变化(未完成)
给类添加方法:避免在运行时收到某个没有实现的方法。
#import "Car+Fly.h"
#import <objc/runtime.h>
void beginToFly(id self, SEL _cmd) {
NSLog(@"begin to fly");
}
@implementation Car (Fly)
+ (BOOL)resolveInstanceMethod:(SEL)sel {
//如果是fly方法,目前没有这个方法的实现,于是就添加一个fly方法
if (sel == @selector(fly)) {
class_addMethod([self class], sel, (IMP)beginToFly, "v@:");
return YES;
}
return [super resolveInstanceMethod:sel];
}
@end
使用kvc访问共有属性,私有属性,keypath,集合操作等。
//set public ivar
[person setValue:@"Peter" forKey:@"name"];
NSLog(@"name:%@",person.name);
//set public _ivar
[person setValue:@"male" forKey:@"_sex"];
NSLog(@"sex:%@",[person valueForKey:@"_sex"]);
//set privacy ivar
[person setValue:@"centry road" forKey:@"address"];
NSLog(@"address: %@",[person valueForKey:@"address"]);
//set privacy _ivar
[person setValue:@"China" forKey:@"_country"];
NSLog(@"country: %@",[person valueForKey:@"_country"]);
//set primary type
[person setValue:[NSNumber numberWithInteger:12] forKey:@"money"];
NSLog(@"set money: %ld",person.money);
NSLog(@"query money: %@",[person valueForKey:@"money"]);
//set keypath
[person setValue:@"Apple" forKeyPath:@"company.name"];
NSLog(@"name of company: %@",[person valueForKeyPath:@"company.name"]);
//collection
person.friends = @[@"Jim",@"Brunce",@"Nancy"];
NSNumber *count = [person valueForKeyPath: @"friends.@count"];
NSLog(@"number of friend: %ld", [count integerValue]);
//start from person
NSNumber *avg = [person valueForKeyPath: @"products.@avg.price"];
NSLog(@"avg of products: %ld", [avg integerValue]);
NSNumber *max = [person valueForKeyPath: @"products.@max.price"];
NSLog(@"max of products: %ld", [max integerValue]);
NSNumber *min = [person valueForKeyPath: @"products.@min.price"];
NSLog(@"min of products: %ld", [min integerValue]);
NSNumber *sum = [person valueForKeyPath: @"products.@sum.price"];
NSLog(@"sum of products: %ld", [sum integerValue]);
访问野指针
运行时改变isa指针
对象,类对象,元类的class方法与object_getClass方法的区别
//object
Person *p = [[Person alloc] init];
NSLog(@"object class: %p",[p class]); //0x104660f18(up to class object)
NSLog(@"object getClass: %p",object_getClass(p)); //0x104660f18(up to class object)
//class object
Class classObj = [p class];
NSLog(@"classObj class: %p",[classObj class]); //0x104660f18(class object self)
NSLog(@"classObj getClass: %p",object_getClass(classObj)); //0x104660ef0(up to meta class object)
//meta class object
Class metaClassObj = object_getClass(classObj);
NSLog(@"metaClassObj class: %p",[metaClassObj class]); //0x104660ef0(meta class object self)
NSLog(@"metaClassObj getClass: %p",object_getClass(metaClassObj)); //0x104ffee08(up to root meta class obj)
//root meta class object
Class rootMetaClassObj = object_getClass(metaClassObj);
NSLog(@"rootMetaClassObj class: %p",[rootMetaClassObj class]); //0x104ffee08(root meta class self)
NSLog(@"rootMetaClassObj getClass: %p",object_getClass(rootMetaClassObj)); //0x104ffee08(root meta class self)
关于NSDictionary的demo
关于appDelegate的几个方法调用的时机
如何判断两个颜色相等
数组里判断是否包含某个对象
关于NSIndexSet的使用
performSelector 可以调用.m文件里的方法
setter 和 getter共存的时候必须要实现 @synthesize
@synthesize name=_name;
- (void)setName:(NSString *)name
{
_name = name;
}
- (NSString *)name
{
return self.name;
}
父视图与子视图的点击
delete the @"" values in a dict
##[31]. string_demo
NSString的一些copy和mutableCopy的操作
给view添加一个分类方法,找到对应的viewController(可顺延父view向上查找)
查看可变数组和不可变数组的copy和mutable copy下的 指针和元素指针。
打印load方法的顺序,包括父类,分类
iOS消息转发实践的demo
比较 static 和 const的不同
比较CGRectInset和CGRectOffset的区别
string的引用计数
@synthesize关键字的使用