链式编程思想-函数式变成思想计算器

编程思想

先简单介绍下目前已知的编程思想。

面向过程:处理事情以过程为核心,一步一步的实现。

面向对象:万物皆对象

链式编程思想:是将多个操作(多行代码)通过点号(.)链接在一起成为一句代码,使代码可读性好。a(1).b(2).c(3)

  • 链式编程特点 : 方法的返回值是block,block必须有返回值(本身对象),block参数(需要操作的值)

  • 代表 : Masonry

响应式编程思想 : 不需要考虑调用顺序,只需要知道考虑结果,类似于蝴蝶效应,产生一个事件,会影响很多东西,这些事件像流一样的传播出去,然后影响结果,借用面向对象的一句话,万物皆是流。

  • 代表 :KVO

函数式编程思想 是把操作尽量写成一系列嵌套的函数或者方法调用

  • 函数式编程特点 : 每个方法必须有返回值(本身对象),把函数或者Block当做参数,block参数(需要操作的值)block返回值(操作结果)

  • 代表 : ReactiveCocoa

-

GCD学习

重新复习GCD

对GCD重新复习一次,加深了解

多线程概念

进程

  • 正在进行中的程序被称为进程,负责程序运行的内存分配
  • 每一个进程都有自己独立的虚拟内存空间

线程

  • 线程是进程中一个独立的执行路径(控制单元)
  • 一个进程中至少包含一条线程,即主线程
  • 可以将耗时的执行路径(如:网络请求)放在其他线程中执行

细说GCD(Grand Central Dispatch)

GCD(Grand Central Dispatch) 介绍

GCD属于系统级的线程管理,在Dispatch queue中执行需要执行的任务性能非常的高。GCD这块已经开源,地址 http://libdispatch.macosforge.org .GCD中的FIFO队列称为dispatch queue,用来保证先进来的任务先得到执行。

  • GCD 能通过推迟昂贵计算任务并在后台运行它们来改善你的应用的响应性能。
  • GCD 提供一个易于使用的并发模型而不仅仅只是锁和线程,以帮助我们避开并发陷阱。
  • GCD 具有在常见模式(例如单例)上用更高性能的原语优化你的代码的潜在能力。

GCD概要

  • 和operation queue一样都是基于队列的并发编程API,他们通过集中管理大家协同使用的线程池。

  • 公开的5个不同队列:运行在主线程中的main queue,3个不同优先级的后台队列(High Priority Queue,Default Priority Queue,Low Priority Queue),以及一个优先级更低的后台队列Background Priority Queue(用于I/O)

  • 可创建自定义队列:串行或并列队列。自定义一般放在Default Priority Queue和Main Queue里。

  • 操作是在多线程上还是单线程主要是看队列的类型和执行方法,并行队列异步执行才能在多线程,并行队列同步执行就只会在这个并行队列在队列中被分配的那个线程执行。

Hello Metal

Metal 简介

Metal和OpenGL ES相似,它也是一个底层API,负责和3D绘图硬件交互。它们之间的不同在于,Metal不是跨平台的。与之相反的,它设计的在苹果硬件上运行得极其高效,与OpenGL ES相比,它提供了更快的速度和更低的开销。


注意: *Metal应用不能跑在iOS模拟器上,它们需要一个设备,设备上装载着苹果A7芯片或者更新的芯片。所以要学习这篇教程,你需要一台这样的设备(iPhone 5S,iPad Air,iPad mini2)来完成代码的测试。*
Metal是一个底层3D绘图API,和OpenGL类似,但是它的开销更低。它是一个GPU上一个简单的封装,所以能够完成几乎所有事情,像在屏幕上渲染一个精灵(sprite)或者是一个3D模型。但你要编写完成这些事情的所有代码。这样麻烦的代价是,你拥有了GPU的力量和控制。没那么底层的游戏框架,像Sprite Kit、Scene Kit或者Unity都是在底层3D绘图API(像是Metal或是OpenGL ES)的基础上构建的。它们提供大部分你需要在游戏中编写的底层封装代码,比如在屏幕上渲染一个精灵(sprite)或者一个3D模型。

Hexo 折腾

首先你要有一个GithubPage

具体如何新建一个代码仓..请自行百度..过于简单不做讨论

Hexo简介

Hexo 是一个轻量的静态博客框架。通过Hexo可以快速生成一个静态博客框架,仅需要几条命令就可以完成,相当方便。
而架设Hexo的环境更简单了 不需要lnmp/lamp这些繁琐复杂的环境 仅仅需要一个简单的http服务器即可使用 或者使用互联网上免费的页面托管服务

官网-> Hexo传送门

Hexo 安装前准备(Mac环境下)

  1. 需要Node.js(如果安装了最好先卸载了再重新装)
  2. 需要Git (Mac环境自备了)
  3. GitHub SSH Key -> 自行百度 -> 用于更新博客(更可理解为git commit)

Setp 1.

  1. node 是通过brew来安装的,所以第一步先安装brew
1
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

brew安装完后就通过它来安装node

1
2
3
4
5
#查看brew 是否安装成功
brew -v

#安装node
brew install node

等待安装完成,测试是否安装成功

1
2
3
4
//查看版本
node -v

npm -v
  1. 安装 Hexo
1
npm install -g hexo-cli

Step 2.

安装完Hexo后,新建一个存放Blog的文件夹
cd进去文件加里面

1
hexo init

//可初始化一个空Hexo项目
//配置看官网
//命令看官网

MultipeerConnectivity框架,近场通信的基本使用

Multipeer connectivity是一个使附近设备通过Wi-Fi网络、P2P Wi-Fi以及蓝牙个人局域网进行通信的框架。互相链接的节点可以安全地传递信息、流或是其他文件资源,而不用通过网络服务。此框架是在iOS7以后推出,旨在替代GameKit下的GKPeerPickerController通信。通过此框架我们可以直接连接同一网络下的设备,让其直接进行类似微信,qq那样的即时通讯效果。

原理

其中通讯的原理,是利用节点来进行广播服务(标示符),其他节点可以通过服务(标示符)发现广播。并对此节点进行连接。在项目中可以将广播和发现放在一起实现,这样既可以发现并连接到其他节点,同时也可以被其他节点所搜索链接。服务的命名规则为由ASCII字母、数字和“-”组成的短文本串,最多15个字符。通常,一个服务的名字应该由应用程序的名字开始,后边跟“-”和一个独特的描述符号

Pod私有库素材管理

​ 首先说说场景,由于以前项目是基于小组件化功能开发最后再拼合起来。某一些模块内需要用到一些UI素材,做法就是在 .podspec中的 resource_bundle中添加素材的路径,执行 pod install后添加到pod里面

1
2
3
4
5
s.resource_bundles = {
#素材路径
#采用的是keyValue形式
'Bundle名字' => ['路径/Resource/Asset/**/**.png']
}

如上,pod install时候就会在路径文件夹下,导入所有.png素材到工程里面.

这是网上普遍做法,且 cocoapod.podspec 文件中也是默认这样导进去素材的.这样导进素材有什么问题呢?

install完,素材只是简单的copy到了项目bundle里面(PS:素材文件夹命名也不正规)。会有以下问题:

  1. 管理起来麻烦
  2. 如果图片资源放到 .xcasset 里面 Xcode 会帮我们自动优化、可以使用 Slicing 等,但是放在 bundle里面并不会压缩素材等,等项目大了,包越来越大

所以,调研了网上做法,踩了坑之后决定写一篇文章记录下做法,这也是 包瘦身 一个方法.由于从0记录了整个过程,我会从创建私有库开始写起,如果你已经有了私有库,直接可以跳去第二步看起

RACCommand粗解

迷之RACCommand

RACCommand 最常用于两个地方,监听按钮点击,网络请求
说实在就是一个执行方法的Block

1 按钮点击,使用 RAC 有两种方式

  • UIControl+RACSignalSupport
1
2
3
//返回一个Signal

- (RACSignal *)rac_signalForControlEvents:(UIControlEvents)controlEvents;
  • UIButton+RACCommandSupport
1
2
3
//定义一个属性(类似Block)

@property(nonatomic, strong) RACCommand *rac_command;

2. 使用SignalForControlEvents来触发

(方法只要点击就触发,等于addTarget)

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

// 按钮是否可点击
RAC(self.commandBtn, enabled) = validSignal;

[[[self.commandBtn rac_signalForControlEvents:UIControlEventTouchUpInside]

// flattenMap 生成新的信号,在信号中可以处理点击事件,并发送结果
//flattenMap map 用于把源信号内容映射成新的内容。

flattenMap:^RACStream *(id value) {
return [self btnClickSignal];
}] subscribeNext:^(id x) {
NSLog(@"====%@", x); // ====按钮点击了
}];

- (RACSignal *)btnClickSignal {

return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {

/**
* 这里可以进行处理按钮点击后的事件,并把想要的结果传递出去
*/
[subscriber sendNext:@"按钮点击了"];

[subscriber sendCompleted];

return nil;
}];
}
  • 上述就是根据 UIControl 的分类信息,进行处理按钮点击事件的第一种方式。但是有一个问题
    • 只有手动点击了按钮,并且是 UIControlEventTouchUpInside 的事件状态下才会执行 block 中的代码。
    • 如果需要主动触发事件呢,而在老代码中,可以手动调用 [self btnClick] ,所以就必须使用第二种方式, RACCommand

3. RACCommand

  • 初始化 rac_command
1
2
3
4
5
6
7
8
9

// 初始化 command, enabled 表示按钮可否点击
RACCommand *command = [[RACCommand alloc] initWithEnabled:validSignal signalBlock:^RACSignal *(id input) {

return [self btnClickSignal];

}];

self.commandBtn.rac_command = command;

正则表达学习

正则表达学习

在线正则表达式测试地址 <- 点我

Sample1:

找出以 lefelefe_x 单词开头,以 wsy 结尾的字符串。比如:lefe name is wsy 是合法的,而 lef name is wsy 是非法的。

正则表达式为:(^(?:lefe|lefe_x)\b.{0,}wsy$)

1.^表示从字符串的开始位置匹配,^(?:lefe|lefe_x) 表示以 lefe 或者 lefe_x 开头;
2. | 表示或,比如 A | B | C ,表示 A,B 和 C 中任意一个;
3. () 表示一个组,(?:) 表示不捕获这个分组;
4. \b 表示匹配一个单词的边界,在这里只能匹配 lefelefe_x;
5.匹配字符串的开头和结尾后,基本上完成了题目的要求,但是字符串lefe(lefe_x)和wsy之间可以是任意字符,. 表示匹配任意字符(不包含换行符),{0,}表示匹配0个或多个字符,则.{0,} 表示匹配0个或多个任意字符(不包含换行符);
6.$表示从字符串的结尾处开始匹配,wsy$ 则表示以 wsy 结尾;

ScrollView、TableView、CollectionView 联动一种实现思路

ScrollView、TableView、CollectionView 联动一种实现思路

首先看看效果:

  1. 带悬停View头部的类型,可以上下拉刷新

scrollViewHoldHeader

2.不带悬停View头部的类型,可以上下拉刷新

(PS.图床上传GIF有问题,经常出现卡死问题,直接运行DEMO比较直观)

Demo地址

联动思路实现

核心思路

大部分处理方案

由于联动是在最底部的 ScrollView 上面添加一个 TableVIew 或者 CollectionView 之类的, 最大难点就是 手势处理 . 嵌套 ScrollView之后,需要一个条件来控制某个具体时刻那个 ScrollView 响应滑动事件。

通常,我们会在 ScrollView 代理方法里面

1
2
3
4
5
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {

//blablabla 逻辑

}

例如,我们会实现这样一个逻辑,最底部有一个 mainScrollViewmainScrollView 上有一个 SubScrollView, 这样就类似一个双 ScrollView嵌套场景了

1
2
3
4
5
6
7
8
9
10
11
//写个伪代码
if (scrollView.contentOffset.y > maxOffsetY){
mainScrollView.isScrollEnabled = false;
subScrollView.isScrollEnabled = true;
}else{
// 当 subScrollView 滑动到顶部时,停止响应,mainScrollView 开始响应
if scrollView.contentOffset.y < 0{
subScrollView.isScrollEnabled = false;
mainScrollView.isScrollEnabled = ture;
}
}

代理方法里面 scrollViewDidScroll 中进行判断,当 mainScrollView 划出了 maxOffsetY ,停止响应滚动,继续滑动时候,就是 subScrollView 响应滚动了

但是,在实际操作上有个很大问题,使用者并不是总能滑动到 maxOffsetY 地方,停下手,进行下一次滑动,如果滑动大于 maxOffsetY 地方, mainScrollView 就会滚动到 maxOffsetY 之后,停止响应,是因为这是一次手势, subScrollView 也不会响应,使用者就有中断感觉,需要第二次滑动才能继续滚动

Thailand Trip

Thailand

Loacation : 普吉岛 - 芭东海滩

时间:

提早 2 小时到达机场

广州 - 曼谷

出发时间 2018-06-13 02:45(北京时间) T1

出发 航班号 起飞 到达 航站楼
广州(CAN)-曼谷(DMK) (白云机场-廊曼机场) SL901 2018-06-13 02:45 2018-06-13 04:20 T1

地铁站: 机场南站

到达时间 04:20 (泰国时间) — (北京时间) 05:20

全程1699公里 时长2小时35分

曼谷廊曼 - 普吉岛

出发时间 2018-06-13 06:15 (泰国时间) — (北京时间) 07:15

出发 航班号 起飞 到达 航站楼
曼谷(DMK)-普吉岛(HKT) (廊曼机场-普吉机场) SL754 2018-06-13 06:15 2018-06-13 07:40

到达时间 07:40 (泰国时间) — (北京时间) 08:40

全程689公里 时长1小时25分

接送

国际航班

国内航班

【国内航站楼】到达的客人,懒猫的工作人员在国内出口的1号门外等待猫王陛下,您找到后出示确认函给工作人员看,工作人员与您核对后将在20分钟左右安排司机过来接猫王陛下,

【国际航站楼】到达的客人请您在一楼取完行李后,走出4号门,懒猫工作人员会在那边举“懒猫旅行”标识的牌等猫王陛下,

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×