轩辕十四

探索科技与创新的个人博客

Swift 是一门面向协议的编程语言,为什么这么说,请看 WWDC 视频 Protocol-Oriented Programming in Swift

通过闭包的方式为 UIControl 添加 action 的实现方式有很多种,例如:

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
extension UIControl {
func listen(_ action: @escaping () -> (), for controlEvents: UIControlEvents) -> AnyObject {
let sleeve = ClosureSleeve(attachTo: self, closure: action, controlEvents: controlEvents)
addTarget(sleeve, action: #selector(ClosureSleeve.invoke), for: controlEvents)
return sleeve
}

func listenOnce(_ action: @escaping () -> (), for controlEvents: UIControlEvents) {
let sleeve = ClosureSleeve(attachTo: self, closure: action, controlEvents: controlEvents)
addTarget(sleeve, action: #selector(ClosureSleeve.invokeOnce), for: controlEvents)
}

func unlisten(sleeve: AnyObject) {
guard let sleeve = sleeve as? ClosureSleeve else { return }
self.removeTarget(sleeve, action: #selector(ClosureSleeve.invoke), for: sleeve.controlEvents)
}
}

private class ClosureSleeve {
let closure: () -> ()
let controlEvents:UIControlEvents
let attachedTo: AnyObject

init(attachTo: AnyObject, closure: @escaping () -> (), controlEvents:UIControlEvents) {
self.attachedTo = attachTo
self.closure = closure
self.controlEvents = controlEvents
objc_setAssociatedObject(attachTo, "[\(arc4random())]", self, .OBJC_ASSOCIATION_RETAIN)
}

@objc func invoke() {
closure()
}

@objc func invokeOnce() {
closure()
attachedTo.unlisten(sleeve: self)
}
}
阅读全文 »

今天在项目中遇到了隐藏 navigationbar 功能的问题,例如:从 A push到 B 页面,A 页面的 navigationbar 是隐藏的,但是 B 页面的 navigationbar 是需要显示的。

一开始我在 A 页面调用 setNavigationBarHidden(true, animated: true) 方法,在 B 页面调用 setNavigationBarHidden(false, animated: true) 方法,虽然能够达到想要的效果,但是对于项目来说是灾难性的。因为如果有多个地方出现这种情况的话,你的代码将会变得十分的杂乱臃肿。

一种好的解决方式是调用 navigationcontroller 的代理:

1
navigationController(_:willShow:animated:)

将这个代理放在项目控制器的基类中,在这里我是放在我的基类 BaseViewController 中。为什么这么做?因为这样可以很好的去掉冗余的代码,不用写的到处都是,我的所有控制器都是继承自 BaseViewController 的,BaseViewController 继承自 UIViewController

下面到了 Show Code 的时候了

阅读全文 »

对 http 的抓包非常的简单,但是对 https 的抓包就有点麻烦了,主要麻烦在证书的安装与设置上。昨天由于有需要去抓https 的包,但是装好证书后,手机一直连不上,特此记录一下。

想要抓取 https 包,首先我们需要在电脑上安装一个 Charles Proxy 的证书

安装 Charles Root Certificate


1、依次点击:Help -> SSL Proxying -> Install Charles Root Certificate

阅读全文 »

尽管很多人了解 RxJava 的基本逻辑,但是在 Observable 链和操作符究竟运行在哪个线程,仍然会有许多困惑。

首先,让我们梳理清晰,在 RxJava 中 .subsribeOn().observeOn() 区别:

  1. .subsribeOn() 操作符可以改变 Observable 应该在哪个调度器上执行任务。
  2. .observeOn() 操作符可以改变 Observable 将在哪个调度器上发送通知。
  3. 另外,你需要知道,默认情况下,链上的操作符将会在调用 .subsribeOn() 的那个线程上执行任务。
阅读全文 »

好消息:Swift 4.2 现已在 Xcode 10 beta 中提供!此版本更新重要的 Swift 4.1 功能,并改进语言以准备 ABI 稳定性。

本教程介绍了 Swift 4.2 中最重要的变化。它需要 Xcode 10,因此请确保你在开始之前下载并安装 Xcode 的最新测试版。

前言


Swift 4.2 与 Swift 4.1 的源代码兼容,但与任何其他版本不兼容。 Apple 设计的 Swift 4.2 是在 Swift 5 中实现 ABI 稳定性的中间步骤,它应该能够在不同 Swift 版本编译的应用和库中保持二进制兼容。在集成到最终的 ABI 之前,ABI 功能会有大量的时间来获得来自社区的反馈。

本教程的部分包含 Swift Evolution 提案编号,如 [SE-0001] 。你可以通过点击每个提案的链接标签来浏览每个更改的详细信息。

阅读全文 »

今天需要去打印店打印东西,但是 U 盘被我格式化成了 APFS 格式,用磁盘管理工具无法格式化成其他的格式,选项中只有 APFS 的选项。我用如下的命令格式化 U 盘:

1
sudo diskutil eraseDisk JHFS+ san /dev/disk3

但是执行命令会报错,错误信息大致是,无法格式化 APFS 容器。

/dev/disk3 是我 U 盘的目录,在执行之前请先确认自己的目录,用如下的命令:

1
diskutil list 
阅读全文 »

理解引用计数


Objective-C 语言使用引用计数来管理内存,也就是说,每个对象都有个可以递增或递减的计数器。如果想使某个对象继续存活,那就递增其引用计数;用完了之后,就递减其计数。计数变为 O,就表示没人关注此对象了,于是,就可以把它销毁。

引用计数工作原理

Objective-C 中,调用 alloc 方法所返回的对象由调用者所拥有。也就是说,调用者已通过 alloc 方法表达了想令该对象继续存活下去的意愿。不过请注意,这并不是说对象此时的保留计数必定是 1。在 alloc 或。initWithInt: 方法的实现代码中,也许还有其他对象也保留了此对象,所以,其保留计数可能会大于 1。能够肯定的是:保留计数至少为 1。保留计数这个概念就应该这样来理解才对。绝不应该说保留计数一定是某个值,只能说你所执行的操作是递增了该计数还是递减了该计数。

1
2
3
4
5
6
7
8
9
NSMutableArray *array = [[NSMutableArray alloc] init];
NSNumber *number = [[NSNumber alloc] initWithInt:1337];

[array addObject:number];
[number release];

// do something with 'array'

[array release];
阅读全文 »

在之前的一篇文章中【iOS 并发,锁,线程同步【一】GCD】,我们讨论了一下 GCD 的并发,锁和线程同步的问题,今天,我们来讨论一下 Operation 的并发与线程同步。

Operation 中,我们一般是将所有的 Operation 添加到 OperationQueue 中进行执行,这里需要注意一点,**Operation 添加到队列当中,默认就是执行的并发操作。我们可以设置队列的最大并发数 maxConcurrentOperationCount。如果我们在 OperationQueue 中想要执行串行任务的话,很简单,将 maxConcurrentOperationCount 设置成为1即可。 maxConcurrentOperationCount 的默认值为-1,那么默认情况下的并发数是多少呢?这个是由系统内存和 CPU 决定的,可能内存多久开多一点,内存少就开少一点。**最大并发数建议 2~3,如果并发数太多会导致 UI 卡顿。

不添加到队列当中的 Operation,我们可以调用 start() 方法开始一个操作,也可以调用 cancel() 取消等待中的操作,注意:已经开始执行的操作是没法取消的。代码示例如下:

1
2
3
4
5
let opt = BlockOperation {
print("Operation")
}
opt.start() // 开始执行任务
opt.cancel() // 取消等待中的任务
阅读全文 »

用 Objective-C 等面向对象语言编程时,“对象”(object)就是“基本构造单元”(building block),开发者可以通过对象来存储并传递数据。在对象之间传递数据并执行任务的过程就叫做“消息传递”(Messaging)。若想编写出高效且易维护的代码,就一定要熟悉这两个特性的工作原理。

当应用程序运行起来以后,为其提供相关支持的代码叫做“Objective-C 运行期环境”(Objective-C runtime),它提供了一些使得对象之间能够传递消息的重要函数,并且包含创建类实例所用的全部逻辑。在理解了运行期环境中各个部分协同工作的原理之后,你的开发水平将会进一步提升。

理解“属性”这一概念


“属性”(property)是 Objective-C 的一项特性,用于封装对象中的数据。Objective-C 对象通常会把其所需要的数据保存为各种实例变量。实例变量一般通过“存取方法”(access method)来访问,也就是 gettersetter 方法。

1
2
3
4
5
6
7
8
@interface EOCPerson: NSOjbect {
@public
NSString *_firstName;
NSString *_lastName;
@private
NSString *_someInternalData;
}
@end
阅读全文 »

Objective-C 语言的起源


Objective-C 与 C++,Java 等面向对象的语言类似,不过在很多地方还是有所差别。Objective-C 使用“消息结构”(messaging structure)而非“函数调用”(function calling)。

消息结构的语言与函数调用的语言关键区别在于:

  • 使用消息结构的语言,其运行时所应执行的代码由运行环境决定,也就是说,在运行时才会检查对象类型。接收一条消息之后,究竟应执行何种代码,由运行期环境而非编译器来决定;
  • 使用函数调用的语言,运行时所执行的代码由编译器决定;

要点:

  • Objective-C 为 C 语言添加了面向对象特性,是其超集。Objective-C 使用动态绑定的消息结构,也就是说,在运行时才会检查对象类型。接收一条消息之后,究竟应执行何种代码,由运行期环境而非编译器来决定。
  • 理解 C 语言的核心概念有助于写好 Objective-C 程序。尤其要掌握内存模型与指针。

在类的头文件中尽量少引入其他头文件


在类的头文件中(.h)我们一般不需要知道引入的某个类的全部细节,这时候,我们可以用 @class 关键字去告诉编译器,知道有一个类名为 xxx 的类就好,不需要关注细节。

这叫做“向前声明”(forward declaring)该类。在实现文件(.m)中我们使用该类时就需要知道其所有细节,这时我们需要用 #import 关键字去导入 xxx 类的头文件。

将引入头文件的时机尽量延后,只有确有需要时才引入,这样就能减少类的使用者所需引入头文件的数量。这样能够一定程度上的减少编译的时间

阅读全文 »
0%