恢复git记录的王牌组合命令

在本地添加了多个远程仓库后,有时会出现本地分支Track(追踪) 不了对应的远程分支的情况(可能是 source 的 bug)。

举个例子
本地有 A,B两个分支,在 source 切到 B 分支后,pull 远程最新 commit 下来,由于 source 上没及时的把远程的 B 分支显示出来,误操作 pull 了远程的 A 分支下来,也没提示警告或错误,然后在B 分支提交了几个 commit,并且切到 A 分支,把 B 分支merge 后,才意识到有问题。当时心里想,小事一桩,用 git reflog 和 git reset 就足够了。

看下事故现场 git reflog 记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1. 8f17e95 HEAD@{28}: commit (merge): Merge branch 'dev' into wxl/dev_3.6.0
2. f5c2290 HEAD@{29}: checkout: moving from dev to wxl/dev_3.6.0
3. b5d537e HEAD@{30}: reset: moving to b5d537e
4. 189e4d3 HEAD@{31}: commit (merge): Merge branch 'wxl/dev_3.6.0' into dev
5. b5d537e HEAD@{32}: pull origin_newchic dev: Fast-forward
6. e12032b (wxl/dev_3.6.0) HEAD@{33}: checkout: moving from wxl/dev_3.6.0 to dev
7. f5c2290 HEAD@{34}: commit: freegift rtl 翻转
8. 5fb503d HEAD@{35}: checkout: moving from wxl/feature_3.7.0_cate to wxl/dev_3.6.0
9. 60f37b2 (origin_newchic/wxl/feature_3.7.0_cate, origin/wxl/feature_3.7.0_cate, wxl/feature_3.7.0_cate) HEAD@{36}: checkout: moving from wxl/feature_cate to wxl/feature_3.7.0_cate
10. 585e703 (origin_newchic/wxl/feature_cate, origin/wxl/feature_cate, wxl/feature_cate) HEAD@{37}: checkout: moving from wxl/dev_3.6.0 to wxl/feature_cate
11. 5fb503d HEAD@{38}: commit (amend): adword 小改,秒杀添加统计
12. 69078ac HEAD@{39}: commit: adword 小改
13. 514a570 HEAD@{40}: commit: 支付成功,统计修正入口位置
14. f608d5b (origin_newchic/wxl/dev_3.6.0, wxl/dev_3.5.3) HEAD@{41}: checkout: moving from dev to wxl/dev_3.6.0
15. e12032b (wxl/dev_3.6.0) HEAD@{42}: pull origin_newchic dev: Fast-forward
16. 5c36b13 (origin/dev) HEAD@{43}: checkout: moving from wxl/dev_3.6.0 to dev

在第15行记录可以看到,错误地 pull 了其它分支,期间 commit 了几次,在第1行记录还可以看出,把其它分支 merge 了过来。

后面用 git reset –hard f5c2290 来回退几个操作的时候,虽然命令显示已经退回到那个点,但 wxl/dev_3.6.0 整个分支的内容都不见了,这就触及我的知识盲区了。先 Mark,以后碰到类似的情况再研究。

1
1. f5c2290 HEAD@{27}: reset: moving to f5c2290

还好,wxl/dev_3.6.0 分支的内容不多,赶紧新建个 recover 分支,用 git reflog 显示记录后,再用 git cherry-pick 一个一个地 pick 过来。

1
2
3
4
5
1. f1d674e HEAD@{15}: cherry-pick: freegift rtl 翻转
2. fded62a HEAD@{16}: cherry-pick: adword 小改,秒杀添加统计
3. f1254ff HEAD@{17}: cherry-pick: adword 小改
4. 485d054 HEAD@{18}: cherry-pick: 支付成功,统计修正入口位置
5. f608d5b (origin_newchic/wxl/dev_3.6.0, wxl/dev_3.5.3) HEAD@{19}: checkout: moving from wxl/dev_3.5.3 to wxl/dev_recover

总结:
遇到分支或 commit 丢失的情况,先用 git reflog 显示 commit 的记录,再用 git cherry-pick xxxxxxx 来合并丢失的内容。这对组合命令几乎可以应对任何情况,但修改了内容而没有 commit 起来的我也没办法了。

利用反射(Reflection)来高效初始化Model的值

Json 转 Model 后,接下来要做的事情

Json转model已是很常见的事情,优秀的第三方库也很多,如YYModel
本文以YYModel为例,在它的基础上,扩展成一个在项目中使用的Model基类。Model基类内置了开关,可对一些常见的对象类型的实例初始化为“空值”(例如,NSString类型赋值为@””,NSArray类型赋值为@[]),这样的做法有2优点:
1、方便,省去了在项目中判断是否为nil的情况
2、安全,避免了一些不必要的异常

核心代码1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
-(NSString *)getPropertyType:(objc_property_t)property {
NSString *propertyType = @"";
unsigned int attrCount;
objc_property_attribute_t *attrs = property_copyAttributeList(property, &attrCount);
for (unsigned int i = 0; i < attrCount; i++) {
if (attrs[i].name[0] == 'T') {
if (attrs[i].value) {
NSString *typeEncoding = [NSString stringWithUTF8String:attrs[i].value];

if (typeEncoding.length > 0) {
NSScanner *scanner = [NSScanner scannerWithString:typeEncoding];
if (![scanner scanString:@"@\"" intoString:NULL]) continue;

NSString *clsName = nil;
if ([scanner scanUpToCharactersFromSet: [NSCharacterSet characterSetWithCharactersInString:@"\"<"] intoString:&clsName]) {
if (clsName.length) propertyType = clsName;
break;
}
}
}
}
}
return propertyType;
}

objc_property_t 类型格式化整理为NSString类型,以方便后续的操作。代码里面的处理做法,在网上参考比较了几种做法,最后发现,还是YYmodel作者的做法最为细腻。取其精华,加工后完成。

核心代码2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
-(void)setSafeValue{
NCBaseModelSafeType safePropertyTypeAll = [self safePropertyType];
if (safePropertyTypeAll == NCBaseModelSafeTypeNone) {
return;
}
NSMutableDictionary *safeTypeDic = [NSMutableDictionary dictionary];
if (safePropertyTypeAll & NCBaseModelSafeTypeNSString) {
[safeTypeDic setObject:@"" forKey:NSStringFromClass([NSString class])];
}
if (safePropertyTypeAll & NCBaseModelSafeTypeNSNumber) {
[safeTypeDic setObject:@(0) forKey:NSStringFromClass([NSNumber class])];
}
if (safePropertyTypeAll & NCBaseModelSafeTypeNSArray) {
[safeTypeDic setObject:@[] forKey:NSStringFromClass([NSArray class])];
}

unsigned int outCount, i;
// 包含所有Property的数组
objc_property_t *properties = class_copyPropertyList([self class], &outCount);
// 遍历每个Property
for (i = 0; i < outCount; i++) {
// 取出对应Property
objc_property_t property = properties[i];

// 获取Property对应的变量名
NSString *propertyName = [NSString stringWithUTF8String:property_getName(property)];
// 获取Property的类型名
NSString *propertyTypeName = [self getPropertyType:property];
// 获取Property的值
id propertyValue = [self valueForKey:propertyName];
// 值为空,才设置默认值
if (!propertyValue) {
NSString *safeTypeKey =propertyTypeName;
id safeTypeValue = safeTypeDic[safeTypeKey];
if (safeTypeValue) {
[self setValue:safeTypeValue forKey:propertyName];
}
}
}
free(properties);
}

代码里面预告设置NSString,NSNumber,NSArray这三种类型的默认值分别为:
@””,@(0),@[]。
思路上采用预先设置默认值到NSDictionary里,这样查找赋值的时间复杂度就为o(1)。函数方法里面有一个在属性数组里操作的情况,因此,总体的时间复杂度为o(n)。

在接口方面比较灵活,默认是不做转换的,避免了一些隐形操作导致的不安全感。需要打开时,在子类中重载方法即可:

1
2
3
-(NCBaseModelSafeType)safePropertyType{
return NCBaseModelSafeTypeNSString | NCBaseModelSafeTypeNSNumber | NCBaseModelSafeTypeNSArray;
}

源码链接NCBaseModel

addChildViewController:的正确用法

现在有ParentVC,OneVC,TwoVC三个controller,想在ParentVC上加载OneVC和TwoVC。
1、如果sub VC还没在父VC上加载过的,则先加载到父VC上,如下

1
2
3
4
[self addChildViewController:content];
content.view.frame = [self frameForContentController];

[self.view addSubview:self.currentClientView];
[content didMoveToParentViewController:self];

2、如果已经加载到父VC上,则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
- (void)cycleFromViewController: (UIViewController*) oldVC
toViewController: (UIViewController*) newVC {
// Prepare the two view controllers for the change.
[oldVC willMoveToParentViewController:nil];
[self addChildViewController:newVC];

// Get the start frame of the new view controller and the end frame
// for the old view controller. Both rectangles are offscreen.
newVC.view.frame = [self newViewStartFrame];
CGRect endFrame = [self oldViewEndFrame];

// Queue up the transition animation.
[self transitionFromViewController: oldVC toViewController: newVC
duration: 0.25 options:0
animations:^{
// Animate the views to their final positions.
newVC.view.frame = oldVC.view.frame;
oldVC.view.frame = endFrame;
}
completion:^(BOOL finished) {
// Remove the old view controller and send the final
// notification to the new view controller.
[oldVC removeFromParentViewController];
[newVC didMoveToParentViewController:self];
}];
}

references:https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/ImplementingaContainerViewController.html

公司的网络组建杂谈

原来公司少人的时候,用个家用的tp-link路由器就可以了。后来人数多了(35人上下),总的终端数达到70个左右,无线终端占9成,网络有时就会断网,甚至有人的笔记本连不进wifi。刚开始不知道原因,折腾了好久,后来才知道这些路由器都有带机量一说(tp-link官网也只有少数的企业路由标出带机量)。

生命在于折腾

折腾了几天的GitHub Pages + Hexo 合成的博客终于修成正果。其中Hexo安装过程真是一堆坑,官网也不说清楚,只能边抹眼泪边查解决方法T_T,顺道换了个好看的主题,看起来心情也会好一些。以后会不定时地上来更新东西,这个博客应该会坚持下去的。 (ง •̀_•́)ง