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 也不会响应,使用者就有中断感觉,需要第二次滑动才能继续滚动

iOS Extentsion 入门实战

最近需求是App接入 Today Extentsion 组件,因为之前没做过这方面,都是摸着石头过河.以下文章都是基于摸索中遇到问题和一些总结,如果有什么不对,请指教一下~

1. App Extensions简介

1.1 什么是App Extensions

从 iOS 8 开始,苹果引入了全新的 App Extension。它是一种扩展,很类似于一些大型软件的插件机制。App Extension 事实上并不是你应用的插件,而是系统的插件,其生命周期是由系统来管理的,所以如果你想做什么坏事还是行不通的…但是 App Extension 分发的载体是应用,也就是说如果你只是单纯想做一个今日面板插件,也需要有个主程序,你的主程序可以什么都不做,也可以提供一些基本的设置和数据。iOS的Extension包括以下:

文章用到的是 Today Extension,用于 iPhone 的今日插件

YYCache阅读学习

YYCache 阅读学习

官网 介绍如下:

高性能 iOS 缓存框架。YYKit 组件之一。

性能:(摘自官网)

iPhone 6 上,内存缓存每秒响应次数 (越高越好):

test15169495589776

iPhone 6 上,磁盘缓存每秒响应次数 (越高越好):

test15169495840565

特性

  • LRU: 缓存支持 LRU (least-recently-used) 淘汰算法。
  • 缓存控制: 支持多种缓存控制方法:总数量、总大小、存活时间、空闲空间。
  • 兼容性: API 基本和 NSCache 保持一致, 所有方法都是线程安全的。
  • 内存缓存
    • 对象释放控制: 对象的释放(release) 可以配置为同步或异步进行,可以配置在主线程或后台线程进行。
    • 自动清空: 当收到内存警告或 App 进入后台时,缓存可以配置为自动清空。
  • 磁盘缓存
    • 可定制性: 磁盘缓存支持自定义的归档解档方法,以支持那些没有实现 NSCoding 协议的对象。
    • 存储类型控制: 磁盘缓存支持对每个对象的存储类型 (SQLite/文件) 进行自动或手动控制,以获得更高的存取性能。

iOS7 以上监听音量键Tips

iOS7 以上监听音量键Tips

iOS7已经废弃 MPMusicPlayerController 这个类与方法 (还是能使用,但对于以后代码迭代,最好替换掉 ) , 如果需要控制系统音量,需要使用 MPVolumeView

以下是一些使用监听音量变化的Tips

需求:音量键拍照 && 拍照无声黑科技

1
2
//代码来看,MPVolumeView 是一个 UIView 的子类
@interface MPVolumeView : UIView <NSCoding>

设计思路:

镜头模块需要监测音量键,音量变化触发拍照功能,为此可以设置一个单例来监测

iOS马赛克图片画笔一种实现思路

iOS马赛克图片画笔一种实现思路

先看下效果:

GIF

功能:

  • 能实现马赛克画笔功能,并提供多种马赛克图案层叠测试
  • 实现了重做,撤销功能
  • 实现了对原图做处理功能,并不是失真保存图案
  • 优化了处理时 CPU 占用太高问题

从DrawRect说起

在我们平时开发中,难免会遇到画笔,画线问题。第一个想到的是使用 drawRect 方法实现功能。 但是drawRect方法会存在较大的内存问题。

举个栗子:
我们需要实现一个画板功能,我们会这样做:

  1. 新建一个画布
  2. touchBegan方法 或者 添加手势方法中 , 保存获得的路径点 , 生成路径
  3. 调用 [setNeedDisplay] , 在 -(void)drawRect 方法里面, 绘制出来.

在大量操作之后,内存、CPU 就会出现明显问题。

那么为什么会有这个问题呢?

高性能iOS应用开发

最近读《高性能iOS应用开发》一书,重新了解了下iOS中内存模型与一些开发中注意事项,并摘抄书中知识点做了下笔记,另外原来不了解方面知识也做了相关资料搜索作笔记补充。(如有错误欢迎指正)

一. 开始

1. 移动应用的性能

1.1 定义性能

性能是非常模糊的术语,高性能有着多重的含义和丰富的解释方式。(需要测量和监控的)性能指标是其中的 一个关注点,(实际上收集数据的)测量是另一个关注点。

1.2 性能指标

性能指标是面向用户的各种属性。每个属性可能是一个或多个可测量工程参数的一个要素。

1.2.1 内存

内存涉及运行应用所需的 RAM 最小值,以及应用消耗的内存平均值和峰值。最小内存值 会严重限制硬件,而更高的内存平均值和峰值意味着更多的后台应用会被强制关闭。
同时还要确保没有泄漏内存。随时间流逝而持续增长的内存消耗意味着,应用很可能会因 为内存不足的异常而崩溃。

1.2.2 电量消耗

电量消耗不仅仅与计算 CPU 周期有关,还包括高效地使用硬件。除了要实现电量消耗最小化,还要确保不会影响用户体验。

1.2.3 初始化时间

应用在启动时应执行刚好够用的任务以完成初始化,从而满足用户的使用需求。执行这些 任务消耗的时间就是应用的初始化时间。 刚好够用是一个开放式用语——正确的平衡点取 决于应用的需要。

1.2.4 执行速度

一旦启动应用,用户总是希望它可以尽可能快地工作。一切必要的处理都应该在尽可能短 的时间内完成。

1.2.5 响应速度

每个应用都应该快速地响应用户交互。在应用中所做的一切优化和权衡最终都应该体现在 响应速度上。

1.2.6 本地存储

针对任何在服务器上存储数据或通过外部来源刷新数据的应用,开发人员应该对本地存储 的使用有所规划,以便应用具备离线浏览的能力。如果你的应用使用了本地存储,那么请提供一个清除数据的选项。

1.2.7 互操作性

用户可能会使用多个应用来完成某个任务,这就需要这些应用直接提供互操作的能力。

1.2.8 网络环境

移动设备会在不同网络环境下使用。为了确保能够提供最好的用户体验,你的应用应当适 应各种网络条件:

  • 高带宽稳定网络

  • 低带宽稳定网络

  • 高带宽不稳定网络

  • 低带宽不稳定网络

  • 无网络

1.2.9 安全

安全对移动应用来说是最重要的,因为敏感信息可能会在应用间共享。因此,对所有通信 以及本地数据和共享数据进行加密就显得尤为重要了。
实现安全需要更多的计算、内存和存储,但这与最大化运行速度、最小化内存和存储使用 的目标相冲突。

iOS音量控制界面控制Tips

iOS音量控制界面控制Tips

AVFoundation 框架提供了播放音频和视频的工具,使用 AVFoundation 基本能满足我们的大部分的播放需求。

在一些需求开发中,通常有一些骚操作需要自定义或者隐藏音量控制界面

MPVolumeView

先看看官方的解释

A slider control used to set the system audio output volume, and a button for choosing the audio output route.

Use a volume view to present the user with a slider control for setting the system audio output volume, and a button for choosing the audio output route. When first displayed, the slider’s position reflects the current system audio output volume. As the user drags the slider, the changes update the volume view. If the user presses the device volume buttons while sound is playing, the slider moves to reflect the new volume.

MPVolumeView是系统级别的音量控制View,但是他并不是一个单例全局获得,不是通过类似 UIApplication 来获得,他只是简单就能获得

1
_systemVolumeView = [[MPVolumeView alloc]initWithFrame:CGRectZero];

当然不是说只是把他设置Frame 为0就可以简单隐藏,也不能通过设置 _systemVolumeView.hidden = YES 隐藏

通常做法就是将其添加到屏幕外位置达到隐藏效果。

此时需要注意的是,如果你把系统的音量控制View隐藏了,切回后台调节音量也是不会显示的,你要_systemVolueView移除,才会重新出现.

ipa 在线下载安装方法(itms-services)

ipa 在线下载安装方法(itms-services)

最近在学习 iOS 逆向这方面知识,逆向完成后,生成一个ipa包,然后再通过 某P助手 安装到手机上.如果想分享给别人使用还要通过真机编译更加麻烦.(当然手机在证书的绑定机子列表里面,并不是免签名越狱机子那种)
然后想起了 蒲公英fir 平台,(代码分发),就好奇它的实现方法,刚好手机购买了 JSBox App,一个非常赞的App,通过自己写脚本可以实现一堆功能。 上面有一个脚本可以本机下载 iCloud 上的 ipa 进行安装,就研究脚本原理.

itms-services

脚本中主要用到的是这个苹果协议 itms-services

itms-services 协议常用于 iOS 企业应用的无线部署,这可在不使用 iTunes 的情况下将内部软件发布或者分享给用户。

流程

html部署

实现在线下载ipa方法其实很简单.首先需要一个网页,safari 浏览器访问然后点击链接下载,如同 蒲公英fir 平台做法. 那么 ,链接 a 标签里面应该写什么呢?

1
<a href="itms-services://?action=download-manifest&url=https://****/***.plist"> xxx </a>

url= 后面plist的链接要求一定是https的,而且必须是公网ssl,自签名及免费的https不可用。
此处推荐 码云 , Github 等自带 https 平台,plist只需上传托管,通过 Raw 形式查看即可获得 plist 的地址,以码云 代码托管平台为例,

点击后即可在浏览器获得地址,然后替换掉 html 标签里面数据

plist 文件

plist文件如何写呢?如下:

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
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>items</key>
<array>
<dict>
<key>assets</key>
<array>
<dict>
<key>kind</key>
<string>software-package</string>
<key>url</key>
<string>http://此处为ipa地址,可以使用http或https</string>
</dict>
</array>
<key>metadata</key>
<dict>
<key>bundle-identifier</key>
<string>*</string>
<key>bundle-version</key>
<string>1.0</string>
<key>kind</key>
<string>software</string>
<key>title</key>
<string>App名字,可随意,网页点击下载时候弹框标识</string>
</dict>
</dict>
</array>
</dict>
</plist>

那么简单的 ipa在线下载就完成了

Your browser is out-of-date!

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

×