正则表达式

界定符

表示一个正则表达式的开始和结束

1
/[0-9]/

在iOS中不加界定符

原子

①可见原子

Unicode 编码表中用键盘输出后可见的字符

1
2
3
4
- 标点;“_?. 等等
- 英文数字a-z,A-Z,0-9
- 数理化公式符号
- 其他可见字符

②不可见原子

Unicode 编码表中用键盘输出后不可见的字符

1
2
3
4
5
- 换行符\n
- 回车 \r
- 制表符 \t
- 空格
- 其他不可见符号

元字符

①原子的筛选方式

1
2
3
- |   匹配两个或者多个分支选择
- [] 匹配方括号中的任意一个原子
- [^] 匹配除方括号中的原子之外的任意字符

②原子的集合

1
2
3
4
5
6
7
- .  匹配除换行符之外的任意字符
- \d 匹配任意一个十进制数字,即[0-9]
- \D 匹配任意一个非十进制数字,即[^0-9]
- \s 匹配一个不可见原子,即[\f\n\r\t\v]
- \S 匹配一个可见原子,即[^\f\n\r\t\v]
- \w 匹配任意一个数字、字母或下划线,即[0-9a-zA-Z_]
- \W 匹配任意一个非数字、字母或下划线,即[^0-9a-zA-Z_]
量词
1
2
3
4
5
6
- {n}   表示其前面的原子恰好出现 n 次
- {n,} 表示其前面的原子至少出现 n 次
- {n,m} 表示其前面的原子恰好出现 n 次,最多出现m次
- * 匹配0次、1次或者多次其之前的原子,即{0,}
- + 匹配一次或者多次其之前的原子,即{1,}
- ? 匹配0次或者1次其之前的原子,即{0,1}

边界控制与模式单元
1
2
3
- ^  匹配字符串开始的位置
- $ 匹配字符串结尾的位置
- () 匹配其中的整体为一个原子

修正模式

常见的修正模式

1
2
3
4
5
- U 懒惰匹配
- i 忽略英文字母大小写
- x 忽略空白
- s 让元字符 ` . ` 匹配包括换行符在内所有字符
- e iOS 暂未知


好以上是正则的简单介绍,详细请看这个:正则表达式30分钟入门教程

iOS 正则表达式

服务器每次返回的时间格式是这个样子的:

1
2016-08-13T13:06:48Z

显示的时候只要年月日 或者是时分秒:

1
2
2016-08-13
13:06:48

这里常用的有两种方法

  1. 使用 NSDateFormatter 格式化,来解析这时间格式的字符串,转换成 NSDate 格式,然后在格式化一次转换成相应的格式(这种方法感觉很蛋疼,折腾了两次);
  2. 使用 NSString 分割方法:
1
- (NSArray<NSString *> *)componentsSeparatedByString:(NSString *)separator;

以 “T” 进行分割,最终得出自己想要的字符串;


这两种方法是常用的方法,但是用起来总感觉不爽,后来想想还可以用 正则表达式,那就试试

使用正则表达式来解析这个时间格式

在iOS中通常使用 “NSRegularExpression” 进行字符串匹配,一般是这个样子:

1
2
3
4
5
6
7
8
     NSString *string = @"字符串xxxx";
NSString *regexString = @"正则表达式";
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regexString options:NSRegularExpressionCaseInsensitive error:nil];
NSArray *matches = [regex matchesInString:string options:NSMatchingReportProgress range:NSMakeRange(0, string.length)];
for (NSTextCheckingResult *match in matches) {
// do something...
}
}

下面我们来写这个正则来匹配出 年月日 和 时分秒。具体的正则写法请自行Google,不过我在这里介绍一个好网站regexper可以分析你写的正则表达式;匹配时间的正则我已经写好了:

1
^(\\d{4}-\\d{1,2}-\\d{1,2})T(\\d{1,2}:\\d{1,2}:\\d{1,2})Z$

在正则表达式中 有group之分,看上面的正则:

1
2
3
4
group#1:
(\\d{4}-\\d{1,2}-\\d{1,2})
group#2:
(\\d{1,2}:\\d{1,2}:\\d{1,2})

group#1 匹配的是年月日,group#2匹配的是时分秒,正则匹配之后,我们是可以分别取出这两个group匹配出来的值的;在iOS中“NSRegularExpression”类,也是有的;下面是匹配:

1
2
3
4
5
6
7
8
9
10
11
12
NSString *string = @"2016-08-13T13:06:48Z";
NSString *regexString = @"^(\\d{4}-\\d{1,2}-\\d{1,2})T(\\d{1,2}:\\d{1,2}:\\d{1,2})Z$";
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regexString options:NSRegularExpressionCaseInsensitive error:nil];
NSArray *matches = [regex matchesInString:string options:NSMatchingReportProgress range:NSMakeRange(0, string.length)];
for (NSTextCheckingResult *match in matches) {
NSString* group0 = [string substringWithRange:[match rangeAtIndex:0]];
NSLog(@"group0 :%@", group0);
NSString* group1 = [string substringWithRange:[match rangeAtIndex:1]];
NSLog(@"group1 :%@", group1);
NSString* group2 = [string substringWithRange:[match rangeAtIndex:2]];
NSLog(@"group2 :%@", group2);
}

使用正则匹配出来之后,NSTextCheckingResult 中 使用 “[match rangeAtIndex:xxx]” 可以取出来。在这里NSTextCheckingResult 中 :

1
2
3
4
NSTextCheckingResult 类属性numberOfRanges 为3
[match rangeAtIndex:0] 匹配的是全量即:2016-08-13T13:06:48Z
[match rangeAtIndex:1] 匹配的是:2016-08-13
[match rangeAtIndex:2] 匹配的是:13:06:48

这下处理不就简单了许多。

CATransition 转场动画

转场动画就是从一个场景以动画的形式过渡到另一个场景,navigation的push就是一种转场方式(后面会介绍如何自定义)。
转场动画一般分为这几个步骤:
(1)初始化转场动画
(2)设置转场类型属性等
(3)设置转场后的新视图并添加动画到图层
下表列出了常用的转场类型(注意私有API是苹果官方没有公开的动画类型,但是目前通过仍然可以使用):

公开API
动画类型 说明 对应常量 是否支持方向设置
fade 淡出效果 kCATransitionFade 是
movein 新视图移动到旧视图上 kCATransitionMoveIn 是
push 新视图推出旧视图 kCATransitionPush 是
reveal 移开旧视图显示新视图 kCATransitionReveal 是
私有API———-私有API只能通过字符串访问
动画类型 说明 对应常量 是否支持方向设置
cube 立方体翻转效果 无 是
oglFlip 翻转效果 无 是
suckEffect 收缩效果 无 否
rippleEffect 水滴波纹效果 无 否
pageCurl 向上翻页效果 无 是
pageUnCurl 向下翻页效果 无 是
cameralIrisHollowOpen 摄像头打开效果 无 否
cameraIrisHollowClose 摄像头关闭效果 无 否
另外对于支持方向设置的动画类型还包含子类型
动画子类型 说明
kCATransitionFromRight 从右侧转场
kCATransitionFromLeft 从左侧转场
kCATransitionFromTop 从顶部转场
kCATransitionFromBottom 从底部转场

下面是一个小例子:

1
2
3
4
5
6
7
8
9
CATransition *transition = [CATransition animation];
transition.duration = 1.0f;
transition.type = @"cube";

transition.subtype = kCATransitionFromRight;
UIView *cubeView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 200, 300)];
cubeView.backgroundColor = [UIColor cyanColor];
[self.view.layer addAnimation:transition forKey:@"cubeView"];
[self.view addSubview:cubeView];

感谢一下博客

http://www.cnblogs.com/kenshincui/p/3972100.html#autoid-3-3-0

CAKeyframeAnimation(关键帧动画)

关键帧动画就是在动画控制过程中开发者指定主要的动画状态,至于各个状态间动画如何进行则由系统自动运算补充(每两个关键帧之间系统形成的动画称为“补间动画”),这种动画的好处就是开发者不用逐个控制每个动画帧,而只要关心几个关键帧的状态即可。
关键帧动画开发分为两种形式:一种是通过设置不同的属性值进行关键帧控制,另一种是通过绘制路径进行关键帧控制。后者优先级高于前者,如果设置了路径则属性值就不再起作用。

看下面的代码,简单的用法:

1
2
3
4
5
6
7
8
CAKeyframeAnimation *keyAnimation = [CAKeyframeAnimation animationWithKeyPath:@“position”];
//设置关键点
NSValue *key1 = [NSValue valueWithCGPoint:_layer.position];
NSValue *key2 = [NSValue valueWithCGPoint:CGPointMake(300, 220)];
NSValue *key3 = [NSValue valueWithCGPoint:CGPointMake(100, 300)];
NSValue *key4 = [NSValue valueWithCGPoint:CGPointMake(300, 400)];
keyAnimation.duration = 5.0f;
[self.layer addAnimation:keyAnimation forKey:@"key"];

当然页可以换成路径:

1
2
3
4
5
6
7
8
9
10
11
//2.设置路径
//绘制贝塞尔曲线
CGMutablePathRef path = CGPathCreateMutable();
//移动到起始点
CGPathMoveToPoint(path, NULL, _layer.position.x, _layer.position.y);
//绘制二次贝塞尔曲线
CGPathAddCurveToPoint(path, NULL, 160, 280, -30, 300, 55, 400);
//设置path属性
keyAnimation.path=path;
//释放路径对象
CGPathRelease(path);

(1) values属性
values属性指明整个动画过程中的关键帧点,例如上例中的key1-key2就是通过values指定的。需要注意的是,起点必须作为values的第一个值。

(2)path属性
作用与values属性一样,同样是用于指定整个动画所经过的路径的。需要注意的是,values与path是互斥的,当values与path同时指定时,path会覆盖values,即values属性将被忽略。

(3)keyTimes
keyTimes:各个关键帧的时间控制,如果你没有显式地对keyTimes进行设置,则系统会默认每条子路径的时间为:ti=duration/(5-1),即每条子路径的duration相等,都为duration的1\4。当然,我们也可以传个数组让物体快慢结合。前面使用values设置了四个关键帧,默认情况下每两帧之间的间隔为:8/(4-1)秒。如果想要控制动画从第一帧到第二针占用时间4秒,从第二帧到第三帧时间为2秒,而从第三帧到第四帧时间2秒的话,就可以通过keyTimes进行设置。keyTimes中存储的是时间占用比例点,此时可以设置keyTimes的值为0.0,0.5,0.75,1.0(当然必须转换为NSNumber,其中首尾必须分别是0和1),也就是说1到2帧运行到总时间的50%,2到3帧运行到总时间的75%,3到4帧运行到8秒结束。

1
keyAnimation.keyTimes = @[@(0),@(0.3),@(0.8),@(1)];

(3) calculationMode属性

calculationMode keys 说明
kCAAnimationLinear calculationMode的默认值,表示当关键帧为座标点的时候,关键帧之间直接直线相连进行插值计算;
kCAAnimationDiscrete 离散的,就是不进行插值计算,所有关键帧直接逐个进行显示;
kCAAnimationPaced 使得动画均匀进行,而不是按keyTimes设置的或者按关键帧平分时间,此时keyTimes和timingFunctions无效;
kCAAnimationCubic 对关键帧为座标点的关键帧进行圆滑曲线相连后插值计算,对于曲线的形状还可以通过tensionValues,continuityValues,biasValues来进行调整自定义,这里的数学原理是Kochanek–Bartels spline,这里的主要目的是使得运行的轨迹变得圆滑;
kCAAnimationCubicPaced 看这个名字就知道和kCAAnimationCubic有一定联系,其实就是在kCAAnimationCubic的基础上使得动画运行变得均匀,就是系统时间内运动的距离相同,此时keyTimes以及timingFunctions也是无效的.
感谢一下博客:

http://www.cnblogs.com/kenshincui/p/3972100.html#autoid-3-1-0

http://www.cnblogs.com/wengzilin/p/4256468.html

http://blog.jobbole.com/69111/

一、简介

CAAnimation的一些基础的知识,复习备用

二、使用步骤

1.使用它需要先添加QuartzCore.framework框架和引入主头文件 QuartzCore/QuartzCore.h (Xcode 6 不需要);

2.初始化一个CAAnimation对象,设置相应的属性;

3.通过调用CALayer的addAnimation:forKey:方法增加CAAnimation对象到CALayer中,这样就能开始执行动画了;

4.通过调用CALayer的removeAnimationForKey:方法可以停止CALayer中的动画.


三、CAAnimation 继承关系与核心类

一般情况下,我们使用的是CAAnimation的子类(CABasicAnimation、CAKeyframeAnimation、CAAnimationGroup、CATransition)

CAAnimation classes

CAAnimation:核心动画的基础类,不能直接使用,负责动画运行时间、速度的控制,本身实现了CAMediaTiming协议;

CAPropertyAnimation:属性动画的基类(通过属性进行动画设置,注意是可动画属性),不能直接使用;

CAAnimationGroup:动画组,动画组是一种组合模式设计,可以通过动画组来进行所有动画行为的统一控制,组中所有动画效果可以并发执行;
CATransition:转场动画,主要通过滤镜进行动画效果设置;
CABasicAnimation:基础动画,通过属性修改进行动画参数控制,只有初始状态和结束状态;
CAKeyframeAnimation:关键帧动画,同样是通过属性进行动画参数控制,但是同基础动画不同的是它可以有多个状态控制;

基础动画、关键帧动画都属于属性动画,就是通过修改属性值产生动画效果,开发人员只需要设置初始值和结束值,中间的过程动画(又叫“补间动画”)由系统自动计算产生。和基础动画不同的是关键帧动画可以设置多个属性值,每两个属性中间的补间动画由系统自动完成,因此从这个角度而言基础动画又可以看成是有两个关键帧的关键帧动画。


四、常用属性

1.duration:它设定开始值到结束值花费的时间。期间会被速度的属性所影响;

2.speed:默认的值为 1.0.这意味着动画播放按照默认的速度。如果你改变这个值为 2.0,动画会用 2 倍的速度播放。这样的影响就是使持续时间减半。如果你指定的持续时间为6秒,速度为2.0,动画就会播放 3 秒钟,一半的 持续时间;

3.removedOnCompletion:这个属性默认为 YES,那意味着,在指定的时间段完成后,动画就自动的从层上移除了。这个一般不用。假如你想要再次用这个动画时,你需要设定这个属性为 NO。这样的话,下次你在通过-set 方法设定动画的属性时,它将再次使用你的动画,而非默认的动画;

4.fillMode:fillMode的作用就是决定当前对象过了非active时间段的行为. 比如动画开始之前,动画结束之后。如果是一个动画CAAnimation,则需要将其removedOnCompletion设置为NO,要不然fillMode不起作用. 下面来讲各个fillMode的意义:

  • kCAFillModeRemoved 这个是默认值,也就是说当动画开始前和动画结束后,动画对layer都没有影响,动画结束后,layer会恢复到之前的状态;
  • kCAFillModeForwards 当动画结束后,layer会一直保持着动画最后的状态;
  • kCAFillModeBackwards 这个和kCAFillModeForwards是相对的,就是在动画开始前,你只要将动画加入了一个layer,layer便立即进入动画的初始状态并等待动画开始.你可以这样设定测试代码,将一个动画加入一个layer的时候延迟5秒执行.然后就会发现在动画没有开始的时候,只要动画被加入了layer,layer便处于动画初始状态;
  • kCAFillModeBoth 理解了上面两个,这个就很好理解了,这个其实就是上面两个的合成.动画加入后开始之前,layer便处于动画初始状态,动画结束后layer保持动画最后的状态;

    5.timingFunction可选的值有:
    • kCAMediaTimingFunctionLinear(线性):匀速,给你一个相对静态的感觉
    • kCAMediaTimingFunctionEaseIn(渐进):动画缓慢进入,然后加速离开
    • kCAMediaTimingFunctionEaseOut(渐出):动画全速进入,然后减速的到达目的地
    • kCAMediaTimingFunctionEaseInEaseOut(渐进渐出):动画缓慢的进入,中间加速,然后减速的到达目的地。这个是默认的动画行为.
1
baseAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];

6.autoreverses:当你设定这个属性为 YES 时,在它到达目的地之后,再原路返回开始值。

7.timeOffset:动画从偏移的地方开始动画,但结束的地方是偏移的地方

8.repeatCount:默认的是 0,意味着动画只会播放一次。如果指定一个无限大的重复次数,使用 1e100f。这个不能和repeatDration属性一块使用。

9.repeatDuration:这个属性指定了动画应该被重复多久。动画会一直重复,直到设定的时间流逝完。它不能和repeatCount一起使用。

10.additive:这个属性根据当前的渲染层的值加上value生成新的渲染的值,也就是动画时present layer的值。

下边的代码的动画效果是一样的,对比下values会有个明确的认识:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- (void)change
{
CAKeyframeAnimation* animation = [CAKeyframeAnimation animationWithKeyPath:@"position.x"];
animation.values = @[@0,@100,@(-100),@100,@0];
animation.keyTimes = @[@0,@(1/6.),@(3/6.),@(5/6.),@1];
animation.duration = 2.f;
animation.additive = YES; //YES把更改的值追加到当前的present层中 keypath+=value ,NO是把更改的值设置成当前present层的值keypath = value
[self.ly.layer addAnimation:animation forKey:@"shaking"];
---------
CAKeyframeAnimation* animation1 = [CAKeyframeAnimation animationWithKeyPath:@"position.x"];
animation1.values = @[@(self.ly1.center.x),@(self.ly1.center.x + 100),@(self.ly1.center.x - 100),@(self.ly1.center.x + 100),@(self.ly1.center.x)];
animation1.keyTimes = @[@0,@(1/6.),@(3/6.),@(5/6.),@1];
animation1.duration = 2.f;
animation1.additive = NO; //YES把更改的值追加到当前的model层中 keypath+=value ,NO是把更改的值设置成当前present层的值keypath = value
[self.ly1.layer addAnimation:animation1 forKey:@"shaking"];
[button animateWithType:arc4random()%3];
[self performSelector:@selector(change) withObject:nil afterDelay:3.f];
}

11.beginTime
无论是图层还是动画,都有一个时间线Timeline的概念,他们的beginTime是相对于父级对象的开始时间. 虽然苹果的文档中没有指明,但是通过代码测试可以发现,默认情况下所有的CALayer图层的时间线都是一致的,他们的beginTime都是0,绝对时间转换到当前Layer中的时间大小就是绝对时间的大小.所以对于图层而言,虽然创建有先后,但是他们的时间线都是一致的(只要不主动去修改某个图层的beginTime),所以我们可以想象成所有的图层默认都是从系统重启后开始了他们的时间线的计时.

但是动画的时间线的情况就不同了,当一个动画创建好,被加入到某个Layer的时候,会先被拷贝一份出来用于加入当前的图层,在CA事务被提交的时候,如果图层中的动画的beginTime为0,则beginTime会被设定为当前图层的当前时间,使得动画立即开始.如果你想某个直接加入图层的动画稍后执行,可以通过手动设置这个动画的beginTime,但需要注意的是这个beginTime需要为 CACurrentMediaTime()+延迟的秒数,因为beginTime是指其父级对象的时间线上的某个时间,这个时候动画的父级对象为加入的这个图层,图层当前的时间其实为[layer convertTime:CACurrentMediaTime() fromLayer:nil],其实就等于CACurrentMediaTime(),那么再在这个layer的时间线上往后延迟一定的秒数便得到上面的那个结果.

1
baseAnimation.beginTime = CACurrentMediaTime() + 1;

12.delegate:动画代理,用来监听动画的执行过程

1
2
3
4
5
6
@interface NSObject (CAAnimationDelegate)
// 动画开始执行的时候触发这个方法
- (void)animationDidStart:(CAAnimation *)anim;
// 动画执行完毕的时候触发这个方法
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;
@end

以上是做动画时常用的属性(当然也包括不常用的);

五、动画类

1.CABasicAnimation
下面是一些简单的使用方法(看一眼就OK了):

1
2
3
4
5
6
7
8
9
CABasicAnimation *baseAnimation = [CABasicAnimation animationWithKeyPath:@"position"];
baseAnimation.delegate = self;
baseAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(150, 450)];
baseAnimation.duration = 5.0f;
baseAnimation.removedOnCompletion = NO;
baseAnimation.speed = 2.0f;
baseAnimation.fillMode = kCAFillModeForwards;
baseAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
[self.layer addAnimation:baseAnimation forKey:@"haha"];

CABasicAnimation 中使用比较多的是KeyPath,下面列出了一些(当然可以通过Xcode 帮助文档搜索“animatable properties“)
keyPath

2.CAAnimationGroup
GroupAnimation可以实现多种动画的组合,在GroupAnimation中的各个动画类型是同时进行的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//缩放动画
CABasicAnimation *scale = [CABasicAnimation animationWithKeyPath:@"transform"];
scale.fromValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];
scale.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.1, 0.1, 1)];

//平移
CABasicAnimation *position = [CABasicAnimation animationWithKeyPath:@"position"];
position.toValue = [NSValue valueWithCGPoint:CGPointMake(150, 450)];

//旋转
CABasicAnimation *rotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
rotation.toValue = [NSNumber numberWithFloat:M_PI_2];

CAAnimationGroup *group = [CAAnimationGroup animation];
group.duration = 5;
group.speed = 1;
group.animations = @[scale,rotation,position];
group.removedOnCompletion = NO;
group.fillMode = kCAFillModeForwards;
[self.layer addAnimation:group forKey:@"group"];
六、最后感谢一下引用的博客

http://geeklu.com/2012/09/animation-in-ios/

http://www.cnblogs.com/wengzilin/p/4256468.html

http://www.cnblogs.com/mjios/archive/2013/04/15/3021039.html

前几天在开发的时候遇到了日期方面的处理,花费了不少时间,踩了点坑,今天就把遇到的写一下.

本文内容

  1. 时间格式
  2. 时间差(两个日期之间的天数、月数、年数差)计算

时间格式

在iOS中 NSDateFormatter 处理时间格式的东东,上次有个需求,就是获取网络请求中cookie的时间

cookie中的时间是这个酱子的:

1
Date:Sat, 21 May 2016 07:57:20 GMT

NSDateFormatter 中有一下格式:

格式 说明
G 公元时代,例如AD公元
yy 年的后2位 如:2016 中的 16
yyyy 完整年 如:2016
MM 月,显示为1-12
MMM 月,显示为英文月份简写,如 Jan
MMMM 月,显示为英文月份全称,如 Janualy
dd 日,2位数表示,如02
d 日,1-2位显示,如 2
EEE 简写星期几,如Sun
EEEE 全写星期几,如Sunday
aa 上下午,AM/PM
H 时,24小时制,0-23
K 时,12小时制,0-11
m 分,1-2位 ( 0-9 是一位 )
mm 分,2位
s 秒,1-2位
ss 秒,2位
S 毫秒
Z GMT

了解了上面的格式,那就容易多了,故格式是:EEE, dd MMM yyyy HH:mm:ss Z

1
2
3
4
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"EEE, dd MMM yyyy HH:mm:ss Z"];

NSDate *date = [formatter dateFromString:@"Sat, 21 May 2016 07:57:20 GMT"];

但是上面的代码 得出的 date 可能是 nil,后面查了下原来是少设置了NSLocale (区域设置)

因为时间格式是英文的,所以:

1
2
3
4
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"EEE, dd MMM yyyy HH:mm:ss Z"];
[formatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]];
NSDate *date = [formatter dateFromString:@"Sat, 21 May 2016 07:57:20 GMT"];

另外,关于是使用 en_US_POSIX还是en_US 可以看这篇文章

当然,你设置成了 zh_CN ,那格式出来的是中文了,如“EEE, dd MMM yyyy HH:mm:ss Z”格式出来的:

1
周六, 21 5月 2016 16:37:57 +0800

时间差计算

要计算两个日期的有多少天,多少个月,如果要自己计算的话,那就爽歪歪了,不过所幸 iOS的日历功能( NSCalendar )可以给我们提供一些便利。

1
2
3
4
5
NSDate *date1 = [formatter dateFromString:@"2016-05-21"];
NSDate *date2 = [formatter dateFromString:@"2013-11-25"];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSDateComponents *components = [gregorian components:NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay fromDate:date2 toDate:date1 options:0];
NSLog(@"year = %ld month = %ld day = %ld",components.year,components.month,components.day);

参考:

http://blog.csdn.net/crayondeng/article/details/8755306

http://www.125135.com/339261.htm

http://www.cnblogs.com/kaysun/p/5466508.html

引言

好久前就已经了解到JSPatch(JSPatch是iOS平台的热修复框架,能够及时的修复线上的一些小bug,iOS应用审核时间之长,大家都懂得),一直以来都没有抽出时间去学习,今天抽出时间来学习下,突然又发现只有官方的一些教程,自己照着写写满满都是泪(崩溃的次数多)。学JSPatch写法,首先大家需要先补一下JavaScript的知识。

基础用法

关于基础的用法大家可以先看官方的Wiki,大致有13个知识点,我这里直接就上用法了。

require

首先,用到哪个类就需要require一下,否则会崩溃,比如UIView、UILabel等等,中间逗号隔开

1
require('UILabel,UIView');

调用OC的方法

因为JavaScript是链式语法,所以说和写OC有很大的不同,写的时候要注意

1
2
3
require('UIView, UIColor');
var view = UIView.alloc().init();//实例方法
var red = UIColor.redColor();//类方法

UIView 有很多的Property,这些Property如何调用呢?

等于调用这个 Property 的 getter / setter 方法,获取时记得加 (),如:

1
2
3
require('UIView, UIColor');
var view = UIView.alloc().init();
view.setBackgroundColor(UIColor.grayColor());

常量、枚举、宏、全局变量

Objective-C 里的常量/枚举不能直接在 JS 上使用,可以直接在 JS 上用具体值代替:

1
2
var label = UILabel.alloc().init();
label.setTextAlignment(1);//这里需要写具体的值

宏也不使用,若定义的宏是一个值,可以在 JS 定义同样的全局变量代替,若定义的宏是程序,可以在JS展开宏

1
2
3
4
5
#define TABBAR_HEIGHT 40
#define SCREEN_WIDTH [[UIScreen mainScreen] bounds].size.height
[view setWidth:SCREEN_WIDTH height:TABBAR_HEIGHT];
//JS
view.setWidth_height(40, UIScreen.mainScreen().bounds().height);

若宏的值是某些在底层才能获取到的值,例如 CGFLOAT_MIN,可以通过在某个类或实例方法里将它返回,或者用添加扩展的方式提供支持,

1
2
3
4
5
6
7
8
@implementation JPMacroSupport
+ (void)main:(JSContext *)context
{
context[@"CGFLOAT_MIN"] = ^CGFloat() {
return CGFLOAT_MIN;
}
}
@end
1
2
require('JPEngine').addExtensions(['JPMacroSupport'])
var floatMin = CGFLOAT_MIN();

当然全局变量也是如此:

1
2
3
4
5
6
static NSString *name;
@implementation JPTestObject
+ (NSString *)name {
return name;
}
@end
1
var name = JPTestObject.name() //拿到全局变量值

defineClass

在 defineClass 里定义 OC 已存在的方法即可覆盖:

1
2
3
4
defineClass('ViewController', {
viewDidLoad: function() {
},
});

如果想调用原方法,在方法名前加 ORIG 即可调用未覆盖前的 OC 原方法:

1
2
3
4
5
defineClass('ViewController', {
viewDidLoad: function() {
self.ORIGviewDidLoad();
},
});

下面是一个UILabel添加到View上的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
require('UILabel,UIView,UIColor,UIFont');
defineClass('ViewController', {
viewDidLoad: function() {
self.ORIGviewDidLoad();
var view = self.view();
var label = UILabel.alloc().initWithFrame({x:100, y:200, width:100, height:100});
label.setFont(UIFont.systemFontOfSize(10));
label.setTextAlignment(1);
label.setText("你好 !");
label.setBackgroundColor(UIColor.grayColor());
view.addSubview(label);
var background = UIView.alloc().initWithFrame({x:100,y:350,width:100,height:100});
background.setBackgroundColor(UIColor.grayColor());
self.setBackgroundView(background);
view.addSubview(self.backgroundView());
},
});

开始的时候一直不知道OC中的“self.view”在JavaScript中怎么调用,试了好久直接调用“self.view()”就行了。





参考:

官方的Wiki

Mac下 搭建博客 之 hexo

引言:

一直在CSDN写博客,但是CSDN对Markdown支持不是很好,而且还是在线,不是很方便。于是决定搭建一个自己的博客,正好github可以免费搭建博客,于是就搭建了一下。

搭建的过程遇到很多的坑,在这里给大家说明,避免大家再次趟雷。

一、安装 HomeBrew

HomeBrew 是 OS X 下的一个程式管理器,需要用他来安装其他程式。

1
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

二、安装 NodeJS

1
brew install node

三、安装 Hexo

可以用 nodejs 自带 npm 安装,切到hexo

1
2
3
npm install hexo -g
hexo init
npm install

注意:在这里运行命令“npm install hexo -g”时可能会有错误

1.错误:

1
2
3
4
5
6
7
8
9
10
11
12
npm WARN locking Error: EACCES, open '/Users/xxxxxx/.npm/_locks/hexo-eabe9ea76eaf84ee.lock'
npm WARN locking at Error (native)
npm WARN locking /Users/xxxxxx/.npm/_locks/hexo-eabe9ea76eaf84ee.lock failed { [Error: EACCES, open '/Users/xxxxxx/.npm/_locks/hexo-eabe9ea76eaf84ee.lock']
npm WARN locking errno: -13,
npm WARN locking code: 'EACCES',
npm WARN locking path: '/Users/xxxxxx/.npm/_locks/hexo-eabe9ea76eaf84ee.lock' }
npm ERR! Darwin 14.1.0
npm ERR! argv "node" "/usr/local/bin/npm" "install" "hexo" "-g"
npm ERR! node v0.12.0
npm ERR! npm v2.10.0

npm ERR! Attempt to unlock /usr/local/lib/node_modules/hexo, which hasn't been locked

解决办法,运行以下命令:

1
sudo npm install --unsafe-perm --verbose -g hexo

2.错误 运行“npm install”时

1
node-pre-gyp install --fallback-to-build

解决办法,运行以下命令:

1
npm install --production

四、安装 GIT

1
brew install git

五、生成 SSH Key:

打开终端:

1
$ ssh -v

查看ssh的版本

1
2
3
4
5
6
7
8
9
OpenSSH_6.2p2, OSSLShim 0.9.8r 8 Dec 2011
usage: ssh [-1246AaCfgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec]
[-D [bind_address:]port] [-e escape_char] [-F configfile]
[-I pkcs11] [-i identity_file]
[-L [bind_address:]port:host:hostport]
[-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port]
[-R [bind_address:]port:host:hostport] [-S ctl_path]
[-W host:port] [-w local_tun[:remote_tun]]
[user@]hostname [command]

这个表明ssh已经安装,在终端输入:

1
$ ssh-keygen

然后系统提示输入文件保存位置等信息,连续敲三次回车即可,生成的SSH key文件保存在中~/.ssh/id_rsa.pub

查看 .ssh,搜索目录

1
$ ls -a ~/.ssh

六、github上添加ssh以及创建项目

在github上添加ssh,然后创建项目

七、Hexo 的设定、更新以及写作命令

1、修改 hexo 根目录下 _config.yml 文件(‘xxxx’为你的账户名称):

1
2
3
4
deploy:
type: git
repository: https://github.com/username/username.github.io.git
branch: master

2、安装 hexo-deployer-git

1
npm install hexo-deployer-git --save

3、更新hexo到最新版

1
npm update hexo -g

4、写作命令,这几个命令都很简单没有什么难度

1
2
3
4
5
建立新文章:hexo n "新文章名"
预览文章:hexo s
生成网页:hexo g
发布文章:hexo d
生成网页并发布文章:hexo d -g

九、安装主题

关于安装主题 可以去看Next,上面有在线的文档,主题配置写的都很详细。


参考博客:

1.http://godera.org/2015/03/16/Mac下程序员博客之Hexo-GitHub-Pages-GitCafe-Pages-DNSPod/
2.http://code.wileam.com/build-a-hexo-blog-and-optimize/

3.Next 主题配置