跳到主要内容

CocoaPods 安装和使用

· 阅读需 4 分钟
BY

最近换了新机器,重新搭建了开发环境,其中当然包括 CocoaPods

装完顺便更新下 CocoaPods 安装文档。

正文

安装

CocoaPods 是用 ruby 实现的,要想使用它首先需要有 ruby 的环境。

升级ruby

查看ruby版本 $ ruby -v

ruby 2.0.0p648 (2015-12-16 revision 53162) [universal.x86_64-darwin16]

CocoaPods需要2.2.2版本及以上的,我们先升级ruby。

使用 rvm 安装 ruby

curl -L get.rvm.io | bash -s stable source ~/.bashrc source ~/.bash_profile

切换 ruby 源

ruby 下载源使用亚马逊的云服务被墙了,切换国内的 ruby-china源<https://ruby.taobao.org/>已经停止维护,详情查看公告):

	$ gem sources --add https://gems.ruby-china.org/ --remove https://rubygems.org/
$ gem sources -l
*** CURRENT SOURCES ***

https://gems.ruby-china.org

安装并切换 ruby

这里不建议安装最新的 2.4.0 版本,因为次版本的 ruby,在xcodebuild 自动打包时,会出现问题! 所以退一步,安装 2.3.3版本~

	rvm install 2.3.3 --disable-binary
rvm use 2.3.3 --default

到此ruby升级完毕.

有关RVM的使用可以看这篇 RVM 使用指南

安装CocoaPods

  1. 安装
		sudo gem install -n /usr/local/bin cocoapods
  1. 升级版本库
		pod setup

这里需要下载版本库(非常庞大),需要等很久

Receiving objects: 72% (865815/1197150), 150.07 MiB | 190.00 KiB/s

或者直接从其他装有cocoapod的电脑中拷贝~/.cocoapods到你的用户目录,然后再 pod setup会节省不少时间

使用

创建 podfile 文件

绝大多数人创建podfile都是用 vim Podfile 命令

其实pod 已经提供了创建 podfile 文件的命令,在工程目录下

pod init

将会自动生成 podfile 文件,并且为你写好了格式,稍做修改就能使用

# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

target 'projectName' do
# Comment the next line if you're not using Swift and don't want to use dynamic frameworks
use_frameworks!

# Pods for projectName

target 'projectNameTests' do
inherit! :search_paths
# Pods for testing
end

target 'projectNameUITests' do
inherit! :search_paths
# Pods for testing
end

end

其中的

target 'projectNameTests' do
inherit! :search_paths
# Pods for testing
end

target 'projectNameUITests' do
inherit! :search_paths
# Pods for testing
end

是指定在单元测试和UI测试时导入的测试框架,若没有使用测试框架可以删除。

修改iOS版本,添加Alamofire

# Uncomment the next line to define a global platform for your project
# platform :ios, '8.0'

target 'projectName' do
# Comment the next line if you're not using Swift and don't want to use dynamic frameworks
use_frameworks!

# Pods for projectName

pod 'Alamofire', '~> 4.4'

end

加载代码库

使用下面的命令,直接在本地版本库中查找对应的代码库信息,不升级版本库,节省时间

pod install --verbose --no-repo-update

若找不到库,再使用下面的命令

pod install

版本号

对版本号的操作除了指定与不指定,你还可以做其他操作:

  • \>0.1 高于0.1的任何版本
  • \>=0.1 版本0.1和任何更高版本
  • <0.1 低于0.1的任何版本
  • <=0.1 版本0.1和任何较低的版本
  • 〜>0.1.2 版本 0.1.2的版本到0.2 ,不包括0.2。 这个基于你指定的版本号的最后一个部分。这个例子等效于>= 0.1.2并且 <0.2.0,并且始终是你指定范围内的最新版本

结语

关于CocoaPods的安装和使用就这样简单的介绍完了,至于更多使用的方法(平时也用不到~)你可以用下面命令查看

$ pod

若对 CocoaPods 的个人仓库感兴趣,也可以看看我的这两篇博客

本文首次发布于 BY Blog, 作者 @柏荧(BY) ,转载请保留原文链接.

强化 swift 中的 print

· 阅读需 2 分钟
BY

在 Swift 中,最简单的输出方法就是使用 print(),在我们关心的地方输出字符串和值。

当程序变得非常复杂的时候,我们可能会输出很多内容,而想在其中寻找到我们希望的输出其实并不容易。我们往往需要更好更精确的输出,这包括输出这个 log 的文件,调用的行号以及所处的方法名字等等。

在 Swift 中,编译器为我们准备了几个很有用的编译符号,它们分别是:

符号类型描述
#fileString包含这个符号的文件的路径
#lineInt符号出现处的行号
#columnInt符号出现处的列
#functionString包含这个符号的方法名字

有了上面的这些编译符号,我们就可以自定义一个输出函数:printm

public func printm(items: Any..., filename: String = #file, function: String = #function, line: Int = #line) {
print("[\((filename as NSString).lastPathComponent) \(line) \(function)]\n",items)
}

因为输出是一个很消耗性能的操作,所以在releass环境下需要将输出函数去掉,将上面的函数换成:

#if DEBUG

public func printm(items: Any..., filename: String = #file, function: String = #function, line: Int = #line) {
print("[\((filename as NSString).lastPathComponent) \(line) \(function)]\n",items)
}

#else

public func printm(items: Any..., filename: String = #file, function: String = #function, line: Int = #line) { }

#endif

参考:

本文首次发布于 BY Blog, 作者 @柏荧(BY) ,转载请保留原文链接.

「知乎」如何理解 <code>document</code> 对象是 <code>HTMLDocument</code> 的实例?

· 阅读需 2 分钟
Hux

这篇文章转载自我在知乎上的回答

谢邀。

首先要理解的是 DOM 是 API,是一组无关编程语言的接口(Interfaces)而非实现(Implementation)。前端平时常说的 DOM 其实只是浏览器通过 ECMAScript(JavaScript)对 DOM 接口的一种实现。

其次要知道的是,DOM 既是为 HTML 制定的,也是为 XML 制定的。而两者各有一些特异的部分,所以作为 DOM 标准基石的 DOM Level 1 其实分为 Core 与 HTML 两个部分。Core 定义了 fundamental interfaces 与 extended interfaces,分别是共用的基础接口与 「XML 拓展包」,而 HTML 部分则全都是「HTML 拓展包」。题主所问到的 Document 接口被定义在 Core 的 fundamental interfaces 中,而 HTMLDocument 接口则定义在 HTML 部分中,且「接口继承」于 Document。

这种继承关系当然是可以在 JavaScript 的 DOM 实现中体现出来的:

// document 是 HTMLDocument 的实例
document instanceof HTMLDocument // true

// document 的 [[prototype]] 指向 HTMLDocument 的原型
document.__proto__ === HTMLDocument.prototype // true

// HTMLDocument 伪类继承于 Document
HTMLDocument.prototype instanceof Document // true
HTMLDocument.prototype.__proto__ === Document.prototype // true

至于 Document 与 HTMLDocument 这两个构造函数,跟 Array、Object 一样都是 built-in 的:

> Document
< function Document() { [native code] }
> HTMLDocument
< function HTMLDocument() { [native code] }

虽然是 native code,但一个有意思的现象是,这两个构造函数之间也是存在原型链的:

// HTMLDocument 的 [[prototype]] 是指向 Document 的
HTMLDocument.__proto__ == Document

// 同理
Document.__proto__ == Node
Node.__proto__ == EventTarget

其作用是实现对静态成员的继承。( ES6 Class 的行为与此完全一致,但这个行为在更早之前就是这样了。)

好了扯远了,总结一下,在 JavaScript 的 DOM 实现中

  • document 是 HTMLDocument 的实例
  • HTMLDocument 继承于 Document

留一个课后作业,有兴趣的话可以看看 Document.prototype 与 HTMLDocument.prototype 里分别都有什么?在不同浏览器里都试试。

以上。

Swift 3.1 的新变化「译」

· 阅读需 12 分钟
BY

Xcode 8.3 和 Swift 3.1 现在已经发布了(3/28)!

可以通过 AppStoreApple Developer 进行下载

Xcode 8.3 优化了 Objective-C 与 Swift 混编项目的编译速度.

Swift 3.1 版本包含一些期待已久的 Swift package manager 功能和语法本身的改进。

如果您没有密切关注 Swift Evolution 进程,请继续阅读 - 本文非常适合您!

在本文中,我将强调Swift 3.1中最重要的变化,这将对您的代码产生重大影响。我们来吧!😃

开始

Swift 3.1与Swift 3.0源代码兼容,因此如果您已经使用Xcode 中的 Edit \ Convert \ To Current Swift Syntax ... 将项目迁移到Swift 3.0,新功能将不会破坏您的代码。不过,苹果已经在Xcode 8.3中支持Swift 2.3。所以如果你还没有从Swift 2.3迁移,现在是时候这样做了!

在下面的部分,您会看到链接的标签,如[SE-0001]。这些是 Swift Evolution 提案号码。我已经列出了每个提案的链接,以便您可以发现每个特定更改的完整详细信息。我建议您尝试在Playground上验证新的功能,以便更好地了解所有更改的内容。

Note:如果你想了解 swift 3.0 中的新功能,可以看这篇文章

语法改进

首先,我们来看看这个版本中的语法改进,包括关于数值类型的可失败构造器Failable Initializers),新的序列函数等等。

可失败的数值转换构造器(Failable Numeric Conversion Initializers)

Swift 3.1 为所有数值类型 (Int, Int8, Int16, Int32, Int64, UInt, UInt8, UInt16, UInt32, UInt64, Float, Float80, Double) 添加了可失败构造器

这个功能非常有用,例如,以安全、可恢复的方式处理外源松散类型数据的转换,下面来看 Student 的 JSON 数组的处理:

class Student {
let name: String
let grade: Int

init?(json: [String: Any]) {
guard let name = json["name"] as? String,
let gradeString = json["grade"] as? String,
let gradeDouble = Double(gradeString),
let grade = Int(exactly: gradeDouble) // <-- 3.1 的改动在这
else {
return nil
}
self.name = name
self.grade = grade
}
}

func makeStudents(with data: Data) -> [Student] {
guard let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments),
let jsonArray = json as? [[String: Any]] else {
return []
}
return jsonArray.flatMap(Student.init)
}

let rawStudents = "[{\"name\":\"Ray\", \"grade\":\"5.0\"}, {\"name\":\"Matt\", \"grade\":\"6\"},
{\"name\":\"Chris\", \"grade\":\"6.33\"}, {\"name\":\"Cosmin\", \"grade\":\"7\"},
{\"name\":\"Steven\", \"grade\":\"7.5\"}]"
let data = rawStudents.data(using: .utf8)!
let students = makeStudents(with: data)
dump(students) // [(name: "Ray", grade: 5), (name: "Matt", grade: 6), (name: "Cosmin", grade: 7)]

Student 类中使用了一个可失败构造器将 grade 属性从 Double 转变为 Int,像这样

let grade = Int(exactly: gradeDouble)

如果gradeDouble不是整数,例如6.33,它将失败。如果它可以用一个正确的表示Int,例如6.0,它将成功。

Note:虽然throwing initializers 可以用来替代 failable initializers。但是使用 failable initializers 会更好,更符合人的思维。

新的序列函数(Sequence Functions)

swift3.1添加了两个新的标准库函数在 Sequence 协议中:prefix(while:)``和prefix(while:)[SE-0045]

构造一个斐波纳契无限序列:

let fibonacci = sequence(state: (0, 1)) {
(state: inout (Int, Int)) -> Int? in
defer {state = (state.1, state.0 + state.1)}
return state.0
}

在Swift 3.0中,您只需指定迭代次数即可遍历fibonacci序列:

// Swift 3.0
for number in fibonacci.prefix(10) {
print(number) // 0 1 1 2 3 5 8 13 21 34
}

在swift 3.1中,您可以使用prefix(while:)drop(while:)获得符合条件在两个给定值之间的序列中的所有元素,就像这样:

// Swift 3.1
let interval = fibonacci.prefix(while: {$0 < 1000}).drop(while: {$0 < 100})
for element in interval {
print(element) // 144 233 377 610 987
}

prefix(while:)返回满足某个谓词的最长子序列。它从序列的开头开始,并停在给定闭包返回false的第一个元素上。

drop(while:) 相反:它返回从给定关闭返回false的第一个元素开始的子序列,并在序列结尾完成。

Note:这种情况,可以使用尾随闭包的写法:

let interval = fibonacci.prefix{$0 < 1000}.drop{$0 < 100}

Concrete Constrained Extensions(姑且翻译为类的约束扩展吧)

Swift 3.1允许您扩展具有类型约束的通用类型。以前,你不能像这样扩展类型,因为约束必须是一个协议。我们来看一个例子。

例如,Ruby on Rails提供了一种isBlank检查用户输入的非常有用的方法。以下是在Swift 3.0中用 String 类型的扩展实现这个计算型属性

// Swift 3.0
extension String {
var isBlank: Bool {
return trimmingCharacters(in: .whitespaces).isEmpty
}
}

let abc = " "
let def = "x"

abc.isBlank // true
def.isBlank // false

如果你希望isBlank计算型属性为一个可选值所用,在swift 3.0中,你将要这样做

// Swift 3.0
protocol StringProvider {
var string: String {get}
}

extension String: StringProvider {
var string: String {
return self
}
}

extension Optional where Wrapped: StringProvider {
var isBlank: Bool {
return self?.string.isBlank ?? true
}
}

let foo: String? = nil
let bar: String? = " "
let baz: String? = "x"

foo.isBlank // true
bar.isBlank // true
baz.isBlank // false

这创建了一个采用 StringStringProvider 协议而在你使用StringProvider扩展可选的 wrapped 类型时,添加isBlank方法。

Swift 3.1中,用来替代协议方法,扩展具体类型的方法像这样:

// Swift 3.1
extension Optional where Wrapped == String {
var isBlank: Bool {
return self?.isBlank ?? true
}
}

这就用更少的代码实现了和原先相同的功能~

泛型嵌套(Nested Generics)

Swift 3.1允许您将嵌套类型与泛型混合。作为一个练习,考虑这个(不是太疯狂)的例子。每当某个团队领导raywenderlich.com想在博客上发布一篇文章时,他会分配一批专门的开发人员来处理这个问题,以满足网站的高质量标准:

class Team<T> {
enum TeamType {
case swift
case iOS
case macOS
}

class BlogPost<T> {
enum BlogPostType {
case tutorial
case article
}

let title: T
let type: BlogPostType
let category: TeamType
let publishDate: Date

init(title: T, type: BlogPostType, category: TeamType, publishDate: Date) {
self.title = title
self.type = type
self.category = category
self.publishDate = publishDate
}
}

let type: TeamType
let author: T
let teamLead: T
let blogPost: BlogPost<T>

init(type: TeamType, author: T, teamLead: T, blogPost: BlogPost<T>) {
self.type = type
self.author = author
self.teamLead = teamLead
self.blogPost = blogPost
}
}

BlogPost内部类嵌套在其对应的Team外部类中,并使两个类都通用。这是团队如何寻找我在网站上发布的教程和文章:

Team(type: .swift, author: "Cosmin Pupăză", teamLead: "Ray Fix", 
blogPost: Team.BlogPost(title: "Pattern Matching", type: .tutorial,
category: .swift, publishDate: Date()))

Team(type: .swift, author: "Cosmin Pupăză", teamLead: "Ray Fix",
blogPost: Team.BlogPost(title: "What's New in Swift 3.1?", type: .article,
category: .swift, publishDate: Date()))

但实际上,在这种情况下,您可以简化该代码。如果嵌套的内部类型使用通用外部类型,那么它默认继承父类的类型。因此,您不需要如此声明:

class Team<T> {
// original code

class BlogPost {
// original code
}

// original code
let blogPost: BlogPost

init(type: TeamType, author: T, teamLead: T, blogPost: BlogPost) {
// original code
}
}

Note:如果您想了解更多关于Swift中的泛型,请阅读我们最近更新的Swift泛型入门的教程

Swift版本的可用性

您可以使用**#if swift(>= N)** 静态构造来检查特定的Swift版本:

// Swift 3.0
#if swift(>=3.1)
func intVersion(number: Double) -> Int? {
return Int(exactly: number)
}
#elseif swift(>=3.0)
func intVersion(number: Double) -> Int {
return Int(number)
}
#endif

然而,当使用Swift标准库时,这种方法有一个主要缺点。它需要为每个受支持的旧语言版本编译标准库。这是因为当您以向后兼容模式运行Swift编译器时,例如您要使用Swift 3.0行为,则需要使用针对该特定兼容性版本编译的标准库版本。如果您使用版本3.1模式编译的,那么您根本就没有正确的代码

因此,@available除了现有平台版本 [SE-0141] 之外,Swift 3.1扩展了该属性以支持指定Swift版本号:

// Swift 3.1

@available(swift 3.1)
func intVersion(number: Double) -> Int? {
return Int(exactly: number)
}

@available(swift, introduced: 3.0, obsoleted: 3.1)
func intVersion(number: Double) -> Int {
return Int(number)
}

这个新功能提供了与intVersionSwift版本有关的方法相同的行为。但是,它只允许像标准库这样的库被编译一次。编译器然后简单地选择可用于所选择的给定兼容性版本的功能。

Note:注意:如果您想了解更多关于Swift 的可用性属性( availability attributes),请参阅我们关于Swift中可用性属性的教程

逃逸闭包(Escaping Closures)

在Swift 3.0 [ SE-0103 ] 中函数中的闭包的参数是默认是不逃逸的(non-escaping)。在Swift 3.1中,您可以使用新的函数withoutActuallyEscaping()将非逃逸闭包转换为临时逃逸。

func perform(_ f: () -> Void, simultaneouslyWith g: () -> Void,
on queue: DispatchQueue) {
withoutActuallyEscaping(f) { escapableF in // 1
withoutActuallyEscaping(g) { escapableG in
queue.async(execute: escapableF) // 2
queue.async(execute: escapableG)

queue.sync(flags: .barrier) {} // 3
} // 4
}
}

此函数同时加载两个闭包,然后在两个完成之后返回。

  1. fg 进入函数后由非逃逸状态,分别转换为逃逸闭包:escapableFescapableG
  2. async(execute:) 的调用需要逃逸闭包,我们在上面已经进行了转换。
  3. 通过运行sync(flags: .barrier),您确保async(execute:)方法完全完成,稍后将不会调用闭包。
  4. 在范围内使用 escapableF and escapableG.

如果你存储临时逃离闭包(即真正逃脱)这将是一个Bug。未来版本的标准库可以检测这个陷阱,如果你试图调用它们。

Swift Package Manager 更新

啊,期待已久的 Swift Package Manage 的更新了!

可编辑软件包(Editable Packages)

Swift 3.1将可编辑软件包(editable packages)的概念添加到Swift软件包管理器 [ SE-0082 ]

swift package edit命令使用现有的Packages并将其转换为editable Packages。使用--end-edit命令将 package manager 还原回 规范解析的软件包(canonical resolved packag)

版本固定(Version Pinning)

Swift 3.1 添加了版本固定的概念[ SE-0145 ]。该 pin 命令 固定一个或所有依赖关系如下所示:

$ swift package pin --all      // 固定所有的依赖
$ swift package pin Foo // 固定 Foo 在当前的闭包
$ swift package pin Foo --version 1.2.3 // 固定 Foo 在 1.2.3 版本

使用unpin命令恢复到以前的包版本:

$ swift package unpin —all
$ swift package unpin Foo

Package manager 将每个依赖库的版本固定信息存储在 Package.pins 文件中。如果该文件不存在,则Package manager 会自动创建。

其他

swift package reset 命令将会把 Package 重置干净。

swift test --parallel 命令 执行测试。

其他改动

在 swift 3.1 中还有一些小改动

多重返回函数

C函数返回两次,例如vforkvfork 已经不用了。他们以有趣的方式改变了程序的控制流程。所以 Swift 社区 已经禁止了该行为,以免导致编译错误。

自动链接失效(Disable Auto-Linking)

Swift Package Manager 禁用了在C语言 模块映射(module maps)中的自动链接的功能:

// Swift 3.0
module MyCLib {
header “foo.h"
link “MyCLib"
export *
}

// Swift 3.1
module MyCLib {
header “foo.h”
export *
}

结语

Swift 3.1改善了Swift 3.0的一些功能,为即将到来的Swift 4.0的大改动做准备。这些包括对泛型,正则表达式,更科学的String等方面的作出极大的改进。

如果你想了解更多,请转到 Swift standard library diffs 或者查看官方的的Swift CHANGELOG,您可以在其中阅读所有更改的信息。或者您可以使用它来了解 Swift 4.0 中的内容!

著作权声明

本文译自 What’s New in Swift 3.1?

@柏荧(BY)进行翻译,首次发布于 BY Blog,转载请保留原文链接.

Mac终端(zsh)下用代码编辑器打开文件或目录

· 阅读需 2 分钟
BY

最近在喵神 onevcat 的直播中发现喵神直接在终端就能用 vsCode 打开当前代码目录,非常方便。

zsh终端中 使用 code .,在 vcCode 打开当前文件目录

正文

配置终端环境

终端环境为:iTerm2 + zsh

zsh 使用 oh_my_zsh 配置

安装zsh

查看你的系统有几种shell

cat /etc/shells

显示

/bin/bash /bin/csh /bin/ksh /bin/sh /bin/tcsh /bin/zsh

安装 oh my zsh

git clone git://github.com/robbyrussell/oh-my-zsh.git ~/.oh-my-zsh cp ~/.oh-my-zsh/templates/zshrc.zsh-template ~/.zshrc

重新打开终端,输入

zsh

即可切换终端,并且发现 oh my zsh 已经帮我们配置好 zsh 了

修改主题

open ~/.zshrc

修改 ZSH_THEME=”robbyrussell”,主题在 ~/.oh-my-zsh/themes 目录下。 修改为

ZSH_THEME="kolo"

可以参照这里进行选择.

设置为默认shell

chsh -s /bin/zsh

修改 zsh 配置文件

$ open ~/.zshrc

在文件中加上这几行代码

对应 atom、SublimeText、与 vcCode。

alias atom='/Applications/Atom.app/Contents/MacOS/Atom' alias subl='/Applications/Sublime\ Text.app/Contents/SharedSupport/bin/subl' alias code='/Applications/Visual\ Studio\ Code.app/Contents/Resources/app/bin/code'

测试

使用 vcCode 打开

$ code .

本文首次发布于 BY Blog, 作者 @柏荧(BY) ,转载请保留原文链接.

文件目录树状(tree)显示

· 阅读需 1 分钟
BY

使用 tree 在终端显示树状文件结构

安装 tree

使用 brew 进行安装

$ brew install tree

使用

  • 直接使用 tree 命令,会在当前文件目录下,递归输出所有文件层级

    $ tree

  • 限制层级

    $ tree -L 2

  • 指定当前目录下的某个文件夹

    $ tree Desktop

导出文件

> 文件名.格式 的形式导出

$ tree -L 1 > tree.md

Swift 代理模式

· 阅读需 2 分钟
BY

Xcode 8.2 | Swift 3.0

在iOS开发中,无论是 Objective-C 还是 SwiftDelegate 有着具足轻重的位置,如TabelViewDelegateTableViewDataSource

Swift 中的代理模式 和 Objective-C 除了语法外,几乎一样。

Objective-C 代理模式

在介绍 Swift 代理模式前,先来看回顾一下 Objective-C 中的代理模式如何实现

Objective-C 中用代理实现反向传值:

委托方(子控制器)

委托方需要实现

  • 创建协议 、声明协议方法
		@protocol SubViewDelegate <NSObject>

- (void)backWithStr:(NSString *) str;

@end
  • 创建一个代理属性
		// weak声明
@property (nonatomic, weak) id<SubViewDelegate> delegate;
  • 执行协议方法
		// 判断代理是实现该方法,避免carsh
if ([self.delegate respondsToSelector:@selector(backWithStr:)]) {
[self.delegate backWithStr:self.textField.text];
}

代理方(主控制器)

代理方需要实现

  • 遵守(继承)协议
		@interface ViewController () <SubViewDelegate>```
- 将代理设为自己

subVC.delegate = self;```

  • 实现代理方法
		- (void)backWithStr:(NSString *)str {
self.label.text = str;
}

Swift 代理模式

Swift 代理模式 与 Objective-C 一样,只是语法不同。

Swift 中用代理实现反向传值:

委托方(子控制器)

  • 创建协议 、声明协议方法
		protocol SubViewDelegate {
func backStr(str: String)
} ```
- 创建一个代理属性

var delegate: SubViewDelegate?```

  • 执行协议方法
		/// 执行代理方法,将值回传
delegate?.backStr(str: textField.text ?? "")

代理方(主控制器)

  • 继承协议
		class ViewController: UIViewController, SubViewDelegate```
- 将代理设为自己

subVC.delegate = self

- 实现代理方法

```swift
func backStr(str: String) {
self.textF.text = str
}

总结

对比可以方法 Swift 代理模式 与 Objective-C 用法完全相同,只是语法发生了变化。

值得一提的是Swift 的扩展 extension可以用来继承协议,实现代码隔离,便于维护。

/// 使用扩展继承协议 实现协议方法 可以分离代码
extension ViewController: SubViewDelegate{
/// 实现代理方法
func backStr(str: String) {
self.textF.text = str
}
}

Demo源码

最后附上Demo源码

如果对你有帮助的话,Star✨下一吧!

Mac 文件的隐藏与显示

· 阅读需 1 分钟
BY

让 Finder 显示隐藏文件和文件夹

显示

$ defaults write com.apple.finder AppleShowAllFiles -boolean true ; killall Finder

隐藏

$ defaults write com.apple.finder AppleShowAllFiles -boolean false ; killall Finder

进阶

创建终端快捷命令

zsh shell 下,创建快捷命令

创建显示命令 fd (fileDisplay)

$ echo "alias fd='defaults write com.apple.finder AppleShowAllFiles -boolean true ; killall Finder'">> ~/.zshrc && source ~/.zshrc

创建隐藏命令 fh(fileHide)

$ echo "alias fd='defaults write com.apple.finder AppleShowAllFiles -boolean false ; killall Finder'">> ~/.zshrc && source ~/.zshrc

使用方法

显示隐藏文件

$ fd 隐藏文件

$ fh

使用 .gitignore 忽略 Git 仓库中的文件

· 阅读需 2 分钟
BY

使用 .gitignore 文件忽略指定文件

.gitignore

在Git中,很多时候你只想将代码提交到仓库,而不是将当前文件目录下的文件全部提交到Git仓库中,例如在MacOS系统下面的.DS_Store文件,或者是Xocde的操作记录,又或者是pod库的中一大串的源代码。这种情况下使用.gitignore就能够在Git提交时自动忽略掉这些文件。

忽略的格式

  • # :此为注释 – 将被 Git 忽略
  • *.a :忽略所有 .a 结尾的文件
  • !lib.a : 不忽略 lib.a 文件
  • /TODO :仅仅忽略项目根目录下的 TODO 文件,不包括 subdir/TODO
  • build/ : 忽略 build/ 目录下的所有文件
  • doc/*.txt : 会忽略 doc/notes.txt 但不包括 doc/server/arch.txt

创建方法

github 上获取

github上整理了一些常用需要的项目中需要忽略的文件配置,根据需要进行获取

https://github.com/github/gitignore.git

与 Xcode 相关的三个文件

  • Xcode.gitignore
  • Objective-C.gitignore
  • Swift.gitignore

Xcode.gitignore忽略 Xcode 配置信息,如操作记录,默认打开窗口等

其他两个在 Xcode.gitignore 基础上针对不同的语言进行忽略

将这些文件重写命名为 .gittignore

	$ mv Swift.gitignore .gittignore

通过 gitignore.io 创建(推荐)

先自定义终端命令:

macOS下默认是\#!/bin/bash

	$ echo "function gi() { curl -L -s https://www.gitignore.io/api/\$@ ;}" >> ~/.bash_profile && source ~/.bash_profile

如果是 #!/bin/zsh

	$ echo "function gi() { curl -L -s https://www.gitignore.io/api/\$@ ;}" >> ~/.zshrc && source ~/.zshrc
使用

在当前终端目录下

	$ gi swift > .gitignore

就会针对 Swifit 类型的工程创建 .gitignore 文件。

Git 代码回滚

· 阅读需 2 分钟
BY

并不适合阅读的个人文档。

先看图:

sourceTreerevert 译为**提交回滚**,作用为忽略你指定的版本,然后提交一个新的版本。新的版本中已近删除了你所指定的版本。

reset重置到这次提交,将内容重置到指定的版本。git reset 命令后面是需要加2种参数的:–-hard–-soft。这条命令默认情况下是 -–soft

执行上述命令时,这该条commit号之 后(时间作为参考点)的所有commit的修改都会退回到git缓冲区中。使用git status 命令可以在缓冲区中看到这些修改。而如果加上-–hard参数,则缓冲区中不会存储这些修改,git会直接丢弃这部分内容。可以使用 git push origin HEAD --force 强制将分区内容推送到远程服务器。

代码回退

默认参数 -soft,所有commit的修改都会退回到git缓冲区 参数--hard,所有commit的修改直接丢弃

$ git reset --hard HEAD^ 回退到上个版本 $ git reset --hard commit_id 退到/进到 指定commit_id 推送到远程

$ git push origin HEAD --force

可以吃的后悔药->版本穿梭

当你回滚之后,又后悔了,想恢复到新的版本怎么办?

git reflog打印你记录你的每一次操作记录

$ git reflog

输出: c7edbfe HEAD@0: reset: moving to c7edbfefab1bdbef6cb60d2a7bb97aa80f022687 470e9c2 HEAD@1: reset: moving to 470e9c2 b45959e HEAD@2: revert: Revert "add img" 470e9c2 HEAD@3: reset: moving to 470e9c2 2c26183 HEAD@4: reset: moving to 2c26183 0f67bb7 HEAD@5: revert: Revert "add img"

找到你操作的id如:b45959e,就可以回退到这个版本

$ git reset --hard b45959e