iOS_Demo保存工作和学习过程中使用,学习到的Demo
[1]. block_pass_value使用block作为方法的参数,实现界面反向传值。[2]. multi_image_cache_and_download使用NSBlockOperation和NSCache,实现tableViewcell里加载网络图片,并带有缓存功能(仿照SDWebImage的逻辑)。
[3]. init_and_initWithFrame对于UIView,即使是用init方法创建实例,也会先调用initWithFrame:方法,然后再调用init方法。
[4]. clean_tableview将tableview的datasource单独抽取出来作为一个类,减少viewcontroller的代码量。cell的绘制方法使用block函数调用。
[5]. associate_object在分类中使用关联对象给类添加属性。
[6]. collectionview_masonry_layout瀑布流的实现,自定义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;
}
[7]. oc_js_interactionOC与JS代码的简单交互。
[8]. access_private_property用KVC和runtime改变私有属性。
1. 定义公有属性和私有属性:
@interface Person : NSObject@property (nonatomic, copy) NSString *name;
//公共属性
@end
@interface Person()
@property (nonatomic, copy) NSString *job;
//私有属性
@end
@implementation Person{
NSString *_country;//私有成员变量
}
2. 使用kvc修改公共属性和私有属性以及私有成员变量
[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);
}
[9]. custom_segue自定义转场动画:
将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];
}];}
[10]. mvvm_kvo_two_way_binding用FBKVOController实现的mvvm的双向绑定。
viewmodel监听model的变化:
//模拟网络请求
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* _Nonnull change) { NSLog(@"viewmodel监听到了model的改变后,立即改变自己被控制器监听的属性"); self.contentStr = [self convertNumber:self.model.number];
}];
});
view监听viewmodel的变化:
- (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* _Nonnull change) {
NSLog(@"当view监听到了viewmodel的改变后,立即改变自己");
self.label.text = self.viewModel.contentStr;
}]; }
return self;}
[11]. multi_thread_communication线程通信的几个例子:NSOperation,GCD,NSObject
[12]. gcd_demo介绍了GCD的API:dispatch_barrier,dispatch_wait,dispatch_group,dispatch_apply等
[13]. autoresizing_demo由xib生成的view默认会跟随父控件大小的变化而变化。如果不让二者有依赖性,需要设置view的autoresizingMask属性。
UIView *subview = [[NSBundle mainBundle] loadNibNamed:@"subview" owner:nil options:nil].firstObject;
//不让xib的view随着父控件的大小而变化subview.autoresizingMask = UIViewAutoresizingNone;
[14].block_lowlevel_analysisblock的底层分析
[15].method_swizzling使用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);
}
[16]. kvo_array_count使用runtime交换方法来同志array count是否变化(未完成)
[17]. class_addMethod_demo给类添加方法:避免在运行时收到某个没有实现的方法。
#import "Car+Fly.h"
#import
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
[18]. kvc_demo
使用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]);
[19]. bad_access_demo
访问野指针