The Bash Shell 变量(初级)

The Bash Shell 变量(初级)

@(Share)[shell]

[TOC]

###前言
我有一个想法,希望通过学习脚本来实现blog的自动创建及发布等操作,
zm推荐shell,pj建议js

常见bash熟悉的特性:

1
2
3
4
5
6
7
8
9
10
11
12
#$:(关于本 shell 的 PID)
#钱字号本身也是个变量喔!这个咚咚代表的是『目前这个 Shell 的线程代号』,亦即是所谓的 PID (Process ID)。 更多的程序观念,我们会在第四篇的时候提及。想要知道我们的 shell 的 PID ,就可以用:『 echo $$ 』即可!出现的数字就是你的 PID 号码。
XcodeYangdeMBP2:~ xcodeyang$ echo $$
10337
#?:(关于上个运行命令的回传值)
#问号也是一个特殊的变量?在 bash 里面这个变量可重要的很! 这个变量是:『上一个运行的命令所回传的值』, 上面这句话的重点是『上一个命令』与『回传值』两个地方。当我们运行某些命令时, 这些命令都会回传一个运行后的代码。一般来说,如果成功的运行该命令, 则会回传一个 0 值,如果运行过程发生错误,就会回传『错误代码』才对!一般就是以非为 0 的数值来取代。
XcodeYangdeMBP2:~ xcodeyang$ echo$
-bash: echo$: command not found
XcodeYangdeMBP2:~ xcodeyang$ echo $?
127 # <== error
XcodeYangdeMBP2:~ xcodeyang$ echo $?
0 # <== success
  • 命令编修能力 (history):
1
2
XcodeYangdeMBP2:~ xcodeyang$ echo $HISTSIZE
500
  • 命令与文件补全功能:

    [tab] 按键的好处

    • 一下和两下的区别
    • 命令与文件路径
1
2
3
4
5
6
7
8
XcodeYangdeMBP2:~ xcodeyang$ x
xar xcodebuild xgettext5.18.pl xmllint xslt-config
xargs xcodeproj xip xpath xsltproc
xattr xcrun xjc xpath5.16 xsubpp
xattr-2.6 xed xml2-config xpath5.18 xsubpp5.16
xattr-2.7 xgettext.pl xml2man xsanctl xsubpp5.18
xcode-select xgettext5.16.pl xmlcatalog xscertadmin xxd
XcodeYangdeMBP2:~ xcodeyang$ x
  • 命令别名配置功能: (alias)
1
2
3
4
5
6
7
XcodeYangdeMBP2:~ xcodeyang$ alias xcodedaniel='ls'
XcodeYangdeMBP2:~ xcodeyang$ cd Documents/
XcodeYangdeMBP2:Documents xcodeyang$ xcodedaniel
GItHub Welcome.itmz bloodsugar 技术部分享
XcodeYangdeMBP2:Documents xcodeyang$ ls
GItHub Welcome.itmz bloodsugar 技术部分享
XcodeYangdeMBP2:Documents xcodeyang$

可变性与方便性

举例:MAIL 变量不同用户设置
yzp -> /var/spool/mail/yzp
cy -> /var/spool/mail/cy
pj -> /var/spool/mail/pj
zm -> /var/spool/mail/zm

1
2
XcodeYangdeMBP2:~ xcodeyang$ echo $USER
xcodeyang

###变量的取用与配置:echo, 变量配置守则, unset

变量的取用就如同上面的范例,利用 echo 就能够读出,只是需要在变量名称前面加上 $ , 或者是以 ${变量} 的方式来取用都可以

####变量的配置守则

  • 变量与变量内容以一个等号『=』来连结,如下所示:

    『yname=zhipingyang』

  • 等号两边不能直接接空格符,如下所示为错误:

    『myname = zhipingyang』或『myname=zhiping yang』

  • 变量名称只能是英文字母与数字,但是开头字符不能是数字,如下为错误:

    『2myname=zhipingyang』

  • 变量内容若有空格符可使用双引号『”』或单引号『’』将变量内容结合起来,但
    双引号内的特殊字符如 $ 等,可以保有原本的特性,如下所示:

    『var=”lang is $LANG”』则『echo $var』可得『lang is en_US』

  • 单引号内的特殊字符则仅为一般字符 (纯文本),如下所示:

    『var=’lang is $LANG’』则『echo $var』可得『lang is $LANG』

  • 可用跳脱字符『 \ 』将特殊符号(如 [Enter], $, \, 空格符, ‘等)变成一般字符;

    XcodeYangdeMBP2:~ xcodeyang$ myname=hello\ world

  • 在一串命令中,还需要藉由其他的命令提供的信息,可以使用反单引号『命令』或 『$(命令)』。特别注意,那个 ` 是键盘上方的数字键 1 左边那个按键,而不是单引号! 例如想要取得核心版本的配置:

    『version=$(uname -r)』再『echo $version』可得『2.6.18-128.el5』

  • 若该变量为扩增变量内容时,则可用 “$变量名称” 或 ${变量} 累加内容,如下所示:

    『PATH=”$PATH”:/home/bin』

  • 若该变量需要在其他子程序运行,则需要以 export 来使变量变成环境变量:

    『export PATH』

  • 取消变量的方法为使用 unset :『unset 变量名称』例如取消 myname 的配置:

    『unset myname』

设置myname变量

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
# 例子一
XcodeYangdeMBP2:~ xcodeyang$ echo $myname
# <==这里并没有任何数据~因为这个变量尚未被配置!是空的!
XcodeYangdeMBP2:~ xcodeyang$ myname = Daniel
-bash: myname: command not found
XcodeYangdeMBP2:~ xcodeyang$ myname=Daniel
XcodeYangdeMBP2:~ xcodeyang$ echo $myname
Daniel
XcodeYangdeMBP2:~ xcodeyang$ bash
bash-3.2$ echo $myname
# <==这里并没有任何数据~因为这个变量是自定义变量(局部变量)
bash-3.2$ exit
exit
XcodeYangdeMBP2:~ xcodeyang$ export myname #修改成环境变量(全局变量)
XcodeYangdeMBP2:~ xcodeyang$ bash
bash-3.2$ echo $myname
Daniel
bash-3.2$ unset myname
bash-3.2$ echo $myname
bash-3.2$ exit
exit
XcodeYangdeMBP2:~ xcodeyang$ echo $myname
Daniel
XcodeYangdeMBP2:~ xcodeyang$
# 例子二
XcodeYangdeMBP2:~ xcodeyang$ echo $HOME
/Users/xcodeyang
XcodeYangdeMBP2:~ xcodeyang$ HOME=$HOME/home/bin
XcodeYangdeMBP2:xcodeyang xcodeyang$ echo $HOME
/Users/xcodeyang/home/bin
# myname=$mynameyes
# 如果没有双引号,name 的内容是 $nameyes 这个变量!
# tip:配错使用control+c取消继续,下面是正确的
# myname="$myname"yes
# myname=${myname}yes <==以此例较佳!
# 猜测一下,那个是对/错
myname="myname's name"
myname='myname's name'
myname=myname\'s\ name
1
2
3
4
5
6
7
8
9
XcodeYangdeMBP2:~ xcodeyang$ echo $name
yzp
XcodeYangdeMBP2:~ xcodeyang$ name="$name is daniel"
XcodeYangdeMBP2:~ xcodeyang$ echo $name
yzp is daniel
XcodeYangdeMBP2:~ xcodeyang$ name='$name is daniel'
XcodeYangdeMBP2:~ xcodeyang$ echo $name
$name is daniel
XcodeYangdeMBP2:~ xcodeyang$

环境变量的功能: env 与常见环境变量说明, set, export

bash 可不只有环境变量喔,还有一些与 bash 操作接口有关的变量,以及用户自己定义的变量存在的. set 除了环境变量之外, 还会将其他在 bash 内的变量通通显示出来哩!信息太多

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
XcodeYangdeMBP2:~ xcodeyang$ newname=daniel
XcodeYangdeMBP2:~ xcodeyang$ name=xcodeyang
XcodeYangdeMBP2:~ xcodeyang$ export name
XcodeYangdeMBP2:~ xcodeyang$ env #<==看这里
TERM_PROGRAM=Apple_Terminal #使用{大写的字母}来配置的变量一般为系统内定需要的变量
SHELL=/bin/bash
TERM=xterm-256color
TMPDIR=/var/folders/1c/hw10tv792_92fz5cswgmzqmc0000gn/T/
Apple_PubSub_Socket_Render=/private/tmp/com.apple.launchd.Zcy3n3bgYL/Render
TERM_PROGRAM_VERSION=361.1
TERM_SESSION_ID=A7EE49FA-7C48-49A4-BA91-8144FACFB146
name=xcodeyang #<==看这里
USER=xcodeyang
SSH_AUTH_SOCK=/private/tmp/com.apple.launchd.Sey2Soe8fS/Listeners
__CF_USER_TEXT_ENCODING=0x1F5:0x0:0x0
PATH=/Users/xcodeyang/.rbenv/shims:/Users/xcodeyang/.rbenv/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/git/bin
PWD=/Users/xcodeyang
XPC_FLAGS=0x0
RBENV_SHELL=bash
XPC_SERVICE_NAME=0
SHLVL=1
HOME=/Users/xcodeyang
LOGNAME=xcodeyang
LC_CTYPE=UTF-8
_=/usr/bin/env
XcodeYangdeMBP2:~ xcodeyang$

###变量的有效范围
环境变量=全局变量
自定义变量=局部变量

为什么环境变量的数据可以被子程序所引用呢?这是因为内存配置的关系!理论上是这样的:

  • 当启动一个 shell,操作系统会分配一记忆区块给 shell 使用,此内存内之变量可让子程序取用
  • 若在父程序利用 export 功能,可以让自定义变量的内容写到上述的记忆区块当中(环境变量);
  • 当加载另一个 shell 时 (亦即启动子程序,而离开原本的父程序了),子 shell 可以将父 shell 的环境变量所在的记忆区块导入自己的环境变量区块当中。

###变量键盘读取、数组与宣告: read, declare, array

我们上面提到的变量配置功能,都是由命令列直接配置的,那么,可不可以让用户能够经由键盘输入? 什么意思呢?是否记得某些程序运行的过程当中,会等待使用者输入 “yes/no” 之类的信息啊?

####read

1
2
3
4
5
6
7
8
9
10
11
12
13
14
XcodeYangdeMBP2:~ xcodeyang$ echo $name
zhipingyang
XcodeYangdeMBP2:~ xcodeyang$ read name
%^$$uhda asuh_uha!@#~ #关键是没有之前那样的语法格式限制
XcodeYangdeMBP2:~ xcodeyang$ echo $name
%^$$uhda asuh_uha!@#~
XcodeYangdeMBP2:~ xcodeyang$
#-p :后面可以接提示字符!
#-t :后面可以接等待的『秒数!』这个比较有趣~不会一直等待使用者啦!
XcodeYangdeMBP2:~ xcodeyang$ read -p "Please keyin your age: " -t 30 agenum
Please keyin your age: 33
XcodeYangdeMBP2:~ xcodeyang$ echo $agenum
33
XcodeYangdeMBP2:~ xcodeyang$

declare / typeset

declare 或 typeset 是一样的功能,就是在『宣告变量的类型』

-a :将后面名为 variable 的变量定义成为数组 (array) 类型
-i :将后面名为 variable 的变量定义成为整数数字 (integer) 类型
-x :用法与 export 一样,就是将后面的 variable 变成环境变量;
-r :将变量配置成为 readonly 类型,该变量不可被更改内容,也不能 unset

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
#示例1:
XcodeYangdeMBP2:~ xcodeyang$ sum=10+20+30
XcodeYangdeMBP2:~ xcodeyang$ echo $sum
10+20+30 #<==默认类型是string
XcodeYangdeMBP2:~ xcodeyang$ declare -i sum=10+20+30
XcodeYangdeMBP2:~ xcodeyang$ echo $sum
60
XcodeYangdeMBP2:~ xcodeyang$ declare -i sum=1/3
XcodeYangdeMBP2:~ xcodeyang$ echo $sum
0 # <==bash 环境中的数值运算,默认最多仅能到达整数形态
XcodeYangdeMBP2:~ xcodeyang$
#示例2
XcodeYangdeMBP2:~ xcodeyang$ declare -ixr sum=20+30 #只读整型环境变量
XcodeYangdeMBP2:~ xcodeyang$ bash
bash-3.2$ echo $sum
50 #子程序里依然可以访问
bash-3.2$ exit
exit
XcodeYangdeMBP2:~ xcodeyang$ sum=30
-bash: sum: readonly variable #不可修改
XcodeYangdeMBP2:~ xcodeyang$
#示例3: 建议直接以 ${数组} 的方式来读取
XcodeYangdeMBP2:~ xcodeyang$ var[1]=$SHELL
XcodeYangdeMBP2:~ xcodeyang$ var[2]=$sum
XcodeYangdeMBP2:~ xcodeyang$ var[3]="helloworld"
XcodeYangdeMBP2:~ xcodeyang$ echo "${var[1]}, ${var[2]}, ${var[3]}"
/bin/bash, 50, helloworld
XcodeYangdeMBP2:~ xcodeyang$

MarkDown的CSS实现配置

灵感

起源于我们现有的博客引擎主题交互很不错,但是排版烂的要死 ,我水平有限这里只是浅显介绍实现修改我们的markdown编译器的一些排版样式

研究方向

自定义一个非标准化,有其他多元素的MarkDown解析器 如下几点:

  • 可选框
    - [ ]
  • 本地图片索引,可控制对齐及大小
    ![Alt text](http://path/to/img.jpg "optional title" 100x200)
    ![Alt text](./1449756974449.png)
  • 标签功能
    @(Share)[css, Markdown]
  • 代码高亮(不同语言)

swift

1
2
3
4
5
private var majorModel = PickMajorModel()
private var subjectModel = OFFKeyNameModel()
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}

objectivec

1
2
3
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, kScreenW, kScreenH)];
scrollView.showsVerticalScrollIndicator = NO;
[scrollView addSubview:self.downMainView];

有一种惨不忍睹的即视感
Alt text

MarkDown来源及实现

Markdown is a plain text format for writing structured documents, based on conventions used for indicating formatting in email and usenet posts. It was developed in 2004 by John Gruber, who wrote the first markdown-to-html converter in Perl, and it soon became widely used in websites. By 2014 there were dozens of implementations in many languages.

见知乎上回答
实现一个markdown解析器需要具备那些知识

###如何简单的改善文字编排的效果

更换博客主题(简单粗暴)

我们使用的博客引擎Hexo来举例,列举下面三个主题

  • landscape
  • hexo-theme-vno-master
  • hexo-theme-yilia-master
更换MarkDown编译器的主题

Mou 举例子,它提供了多套markdown语法下的排版样式
手动新创建一个CSS文本布局配置 Blog
Alt text

CSS配置文件修改

详细配置参数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
html { font-size: 62.5%; }
html, body { height: 100%; }
body {
font-family: Helvetica, Arial, sans-serif;
font-size: 150%;
line-height: 1.3;
color: #f6e6cc;
width: 700px;
margin: auto;
background: #27221a;
position: relative;
padding: 0 30px;
}

多级标题配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
h1 {
font-size: 28px;
color: black; }
h2 {
font-size: 24px;
border-bottom: 1px solid #cccccc;
color: black; }
h3 {
font-size: 18px; }
h4 {
font-size: 16px; }
h5 {
font-size: 14px; }
h6 {
color: #777777;
font-size: 14px; }

表格

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
table {
padding: 0;border-collapse: collapse; }
table tr {
border-top: 1px solid #cccccc;
background-color: white;
margin: 0;
padding: 0; }
table tr:nth-child(2n) {
background-color: #f8f8f8; }
table tr th {
font-weight: bold;
border: 1px solid #cccccc;
margin: 0;
padding: 6px 13px; }
table tr td {
border: 1px solid #cccccc;
margin: 0;
padding: 6px 13px; }
table tr th :first-child, table tr td :first-child {
margin-top: 0; }
table tr th :last-child, table tr td :last-child {
margin-bottom: 0; }

代码高亮

1
2
3
4
5
6
7
8
9
10
11
12
13
14
code, tt {
margin: 0 2px;
padding: 0 5px;
white-space: nowrap;
border: 1px solid #eaeaea;
background-color: #f8f8f8;
border-radius: 3px; }
pre code {
margin: 0;
padding: 0;
white-space: pre;
border: none;
background: transparent; }

IM中输入框的优化方案实现

IM中输入框的优化方案实现

以下图的输入框为例

stand

输入框的呈现方式选择

以下两个方法对比

  • Keyboard的inputAccessoryView

相对推荐的方法,有更好的丰富的交互效果

可以与scrollView的一些属性直接绑定

  • InputView的frame适应

传统的方法

优点:灵活控制显示位置

缺点:过多的计算frame

###InputAccessoryView方式

案例见GitHub的Demo

iOS的输入源都有输入源(keyboard及keyboard的配件InputAccessoryView),那通常的方法是输入源控件(Textfield、TextView等)使用一般的InputView的frame适应

解释几个技巧点

  • InputView( 输入源 )的父视图作为该InputView的InputAccessoryView,要避免相互引用
  • 巧用第三方不可见的InputView在适当时间点转移第一响应者给可见的InputView
  • 完成编辑时去除第一响应者(注意iOS9下键盘响应逻辑视图层级都发生了变化)

主要代码

simulator screen shot nov 27 2015 4 17 38 pm

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
// 单例初始化
+ (UUInputAccessoryView*)sharedView {
static dispatch_once_t once;
static UUInputAccessoryView *sharedView;
dispatch_once(&once, ^ {
sharedView = [[UUInputAccessoryView alloc] init];
sharedView->btnBack = [UIButton buttonWithType:UIButtonTypeCustom];
sharedView->btnBack.frame = CGRectMake(0, 0, UUIAV_MAIN_W, UUIAV_MAIN_H);
[sharedView->btnBack addTarget:sharedView action:@selector(dismiss) forControlEvents:UIControlEventTouchUpInside];
sharedView->btnBack.backgroundColor=[UIColor clearColor];
UIToolbar *toolbar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, UUIAV_MAIN_W, 44)];
sharedView->inputView = [[UITextField alloc]initWithFrame:CGRectMake(UUIAV_Edge_Hori, UUIAV_Edge_Vert, UUIAV_MAIN_W-UUIAV_Btn_W-4*UUIAV_Edge_Hori, UUIAV_Btn_H)];
sharedView->inputView.borderStyle = UITextBorderStyleRoundedRect;
sharedView->inputView.returnKeyType = UIReturnKeyDone;
sharedView->inputView.clearButtonMode = UITextFieldViewModeWhileEditing;
sharedView->inputView.enablesReturnKeyAutomatically = YES;
sharedView->inputView.delegate = sharedView;
[toolbar addSubview:sharedView->inputView];
sharedView->assistView = [[UITextField alloc]init];
sharedView->assistView.delegate = sharedView;
sharedView->assistView.returnKeyType = UIReturnKeyDone;
sharedView->assistView.enablesReturnKeyAutomatically = YES;
[sharedView->btnBack addSubview:sharedView->assistView];
sharedView->assistView.inputAccessoryView = toolbar;
sharedView->BtnSave = [UIButton buttonWithType:UIButtonTypeCustom];
sharedView->BtnSave.frame = CGRectMake(UUIAV_MAIN_W-UUIAV_Btn_W-2*UUIAV_Edge_Hori, UUIAV_Edge_Vert, UUIAV_Btn_W, UUIAV_Btn_H);
sharedView->BtnSave.backgroundColor = [UIColor clearColor];
[sharedView->BtnSave setTitle:@"确定" forState:UIControlStateNormal];
[sharedView->BtnSave setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[sharedView->BtnSave addTarget:sharedView action:@selector(Done) forControlEvents:UIControlEventTouchUpInside];
[toolbar addSubview:sharedView->BtnSave];
});
CGRectGetHeight([UIScreen mainScreen].bounds);
return sharedView;
}

实现逻辑代码

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
40
41
42
43
44
45
46
47
48
49
+ (void)showKeyboardType:(UIKeyboardType)type content:(NSString *)content Block:(UUInputAccessoryBlock)block
{
[[UUInputAccessoryView sharedView] show:block
keyboardType:type
content:content];
}
- (void)show:(UUInputAccessoryBlock)block keyboardType:(UIKeyboardType)type content:(NSString *)content
{
UIWindow *window=[UIApplication sharedApplication].keyWindow;
[window addSubview:btnBack];
inputBlock = block;
inputView.text = content;
inputView.keyboardType = type;
assistView.keyboardType = type;
[assistView becomeFirstResponder];
shouldDismiss = NO;
[[NSNotificationCenter defaultCenter] addObserverForName:UIKeyboardDidShowNotification
object:nil
queue:nil
usingBlock:^(NSNotification * _Nonnull note) {
if (!shouldDismiss) {
[inputView becomeFirstResponder];
}
}];
}
- (void)Done
{
[inputView resignFirstResponder];
!inputBlock ?: inputBlock(inputView.text);
[self dismiss];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[self Done];
return NO;
}
- (void)dismiss
{
shouldDismiss = YES;
[inputView resignFirstResponder];
[btnBack removeFromSuperview];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}

InputView的frame适应

案例见GitHub的Demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 键盘响应布局
@objc func keyboardFrameChanged(notification: NSNotification) {
let dict = NSDictionary(dictionary: notification.userInfo!)
let keyboardValue = dict.objectForKey(UIKeyboardFrameEndUserInfoKey) as! NSValue
let bottomDistance = mainScreenSize().height - keyboardValue.CGRectValue().origin.y
let duration = Double(dict.objectForKey(UIKeyboardAnimationDurationUserInfoKey) as! NSNumber)
UIView.animateWithDuration(duration, animations: {
self.inputViewConstraint!.constant = -bottomDistance
self.view.layoutIfNeeded()
}, completion: {
(value: Bool) in
self.chatTableView.scrollToBottom(animation: true)
})
}

ScrollView下拉动态修改keyboard(InputView)的frame

常见隐藏keyboard的一些方式

  • TouchBeigin
  • DidDrag
  • EndDrag
  • Interactive

iOS7 开始,ScrollView提供

1
2
3
4
5
6
@available(iOS 7.0, *)
public enum UIScrollViewKeyboardDismissMode : Int {
case None
case OnDrag // dismisses the keyboard when a drag begins
case Interactive // the keyboard follows the dragging touch off screen, and may be pulled upward again to cancel the dismiss
}

所以在ScrollView上添加scrollView.keyboardDismissMode = UIScrollViewKeyboardDismissMode.Interactive就可以了。
效果详见iOS7及以上原生设备的短信滑动消失键盘的交互

周精益分享 - Swift入门专题

『图像和滤镜』 - 图像选择器

我们可以使用以下常规的图像获取方式

Alt text

图库与相册

Alt text

系统自带

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let sheet = UIAlertController(title: "图片选择", message: "简单版的三种选择", preferredStyle: .ActionSheet)
// 判断设备是否支持相机(iPod & Simulator)
if (UIImagePickerController.isSourceTypeAvailable(.Camera)) {
sheet.addAction(UIAlertAction.init(title: "Camera", style: .Default, handler: { _ in
self.showPhotoes(.Camera)
}))
}
sheet.addAction(UIAlertAction.init(title: "PhotoLibrary", style: .Default, handler: { _ in
self.showPhotoes(.PhotoLibrary)
}))
sheet.addAction(UIAlertAction.init(title: "SavedPhotosAlbum", style: .Default, handler: { _ in
self.showPhotoes(.SavedPhotosAlbum)
}))
sheet.addAction(UIAlertAction.init(title: "Cancel", style: .Cancel, handler: nil))
presentViewController(sheet, animated: true, completion: nil)
}
1
2
3
4
5
6
7
8
func showPhotoes(source: UIImagePickerControllerSourceType) {
let controller = UIImagePickerController()
controller.delegate = self
controller.sourceType = source
controller.allowsEditing = source == .SavedPhotosAlbum ? true:false
self.presentViewController(controller, animated: true, completion: nil)
}

UIImagePickerController的代理

1
2
3
4
5
6
7
8
func imagePickerControllerDidCancel(picker: UIImagePickerController) {
dismissViewControllerAnimated(true, completion: nil)
}
// 非常坑,这个方法废弃了但代码提示只有它
// func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?) {
// }
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
}

#####info字典介绍

1
2
3
4
5
6
7
8
9
10
UIImagePickerControllerMediaType: String
UIImagePickerControllerOriginalImage: UIImage
UIImagePickerControllerEditedImage: UIImage
UIImagePickerControllerCropRect: NSValue -> CGRect
// MediaURL只为视频提供
UIImagePickerControllerMediaURL: NSURL
// LivePhoto是一张图片,保留那个moment的前后动作和声音
UIImagePickerControllerLivePhoto: String
// 摄像摄影时返回media的信息字典
UIImagePickerControllerMediaMetadata: NSDictionary

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// SavedPhotosAlbum 的 info 示例
▿ 5 elements
▿ [0] : 2 elements
- .0 : "UIImagePickerControllerCropRect"
▿ [1] : 2 elements
- .0 : "UIImagePickerControllerOriginalImage"
▿ [2] : 2 elements
- .0 : "UIImagePickerControllerReferenceURL"
- .1 : assets-library://asset/asset.JPG?id=99D53A1F-FEEF-40E1-8BB3-7DD55A43C8B7&ext=JPG
▿ [3] : 2 elements
- .0 : "UIImagePickerControllerMediaType"
- .1 : public.image
▿ [4] : 2 elements
- .0 : "UIImagePickerControllerEditedImage"

自定义

Alt text

遍历相册的所有图片

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
// AssetsLibrary.framework
// ALAssetsLibrary 的使用,但是它慢慢的被放弃了
func loadLocalPhotoes(){
var countOne = 0
//ALAssetsGroupSavedPhotos表示只读取相机胶卷(ALAssetsGroupAll则读取全部相簿)
assetsLibrary.enumerateGroupsWithTypes(ALAssetsGroupSavedPhotos, usingBlock: {
(group: ALAssetsGroup!, stop) in
print("is goin")
if group != nil {
let assetBlock : ALAssetsGroupEnumerationResultsBlock = {
(result: ALAsset!, index: Int, stop) in
if result != nil {
self.assets.append(result)
countOne++
}
}
group.enumerateAssetsUsingBlock(assetBlock)
print("assets:\(countOne)")
self.startChangeLocalImages(0)
}
}, failureBlock: { (fail) in
print(fail)
})
}
// 展现本地图片
func startChangeLocalImages(var index: Int){
if index==assets.count {
index = 0
}
let myAsset = assets[index]
let image = UIImage(CGImage:myAsset.thumbnail().takeUnretainedValue())
self.backImageView.image = image
let popTime = dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC)))
dispatch_after(popTime, dispatch_get_main_queue()) {
self.startChangeLocalImages(index+1)
}
}

iOS9 开始使用新库
PHPhotoLibrary

周精益分享 - 程序员装逼指南

『图像和滤镜』

图像

常见的图像格式

  • png(Portable Network Graphic)便携式网络图形格式
  • tiff、tif(Tagged Image File Format)标记图像文件格式
  • jpg、jpeg(Joint Photographic Experts Group)联合摄影专家组
  • gif(Graphic Interchange Format)图形交换格式

图像实例化

  • imageNamed:

    使用频率高,内存缓存优化

  • imageWithContentsOfFile:

    单次使用,暂时不清楚如何支持ImageAssert下的图片路径

  • imageWithData:

    本地或网络的文件数据加载

  • imageWithCGImage:

    绘制生成图,代码如下

1
2
3
4
5
// 旧图局部裁剪
CGImageRef myImageRef = [oldImage CGImageRef];
CGRect subRect = CGRectMake(20, 20, 100, 100);
CGImageRef cgCrop = CGImageCreateWithImageInRect(myImageRef, subRect);
UIImage *imageCrop = [UIImage imageWithCGImage:cgCrop];

显示图像

屏幕的缩放因子,导致我们需要@2x及@3x图,对视图截图操作也同样需要针对Retina及plus优化

1
2
3
4
5
6
7
8
9
10
11
- (UIImage*)screenShotBy:(UIImageView*)imagView
{
// UIGraphicsBeginImageContext(imagView.bounds.size);
// 2表示Retina,3表示plus分辨率,1正常,0则是当前设备的缩放因子
// YES 表示不包含图像的alpha通道
UIGraphicsBeginImageContextWithOptions((imagView.bounds.size), YES, 2);
[imagView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage*image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}

contentModel

图像内容展现方式

  • UIViewContentModelScaleToFill(默认)
  • UIViewContentModelScaleAspectFill(下拉放大)
  • UIViewContentModelScaleAspectFit
  • UIViewContentModelCenter (一些停靠模式)
  • UIViewContentModelTop/Bottom
  • UIViewContentModelLeft/Right
拉伸属性

代码

1
2
3
4
5
// 方法一
image=[oldIconImage stretchableImageWithLeftCapWidth:10 topCapHeight:12];
// 方法二
image = [oldIconImage resizableImageWithCapInsets:UIEdgeInsetsMake(17, 17, 17, 25)];

ImageAssert

Alt text
使用slicing,小变大无视差
Alt text


图像选择器

系统自带

自定义


滤镜

人脸识别

周精益分享 - 英语

英语,程序员

网站

  • iTalki

    语言交换及专业老师订课辅导的网站

  • YouTube一个订阅号

    比较有吸引力的老师,他的同事频道也很不错

  • rayWenderlich

    主要是iOS方面的,安卓覆盖一些。涵盖文字、视频、播客三方面

APP

  • 飞鱼口语

    国内开发的一个及时练习口语的APP,主要是方便

  • 每日英语听力(欧陆词典推出的)

    radio 模块很不错,资源不算多但比较有质量。

  • Podcast

    • 圆桌会议(RoundTable)
    • rayWenderlich (程序员职业发展及新技术点探讨,英式口语)

工具

  • Skype 和志同道合的人交流,练习口语

EF Education

  • 网站地址

    想小试牛刀的记得想我拿一下账号密码

周精益分享-谈谈未来、梦想、职业规划

兴趣主导,快乐很重要 - 杨志平

  • 兴趣

    • 在失去当前工作兴趣之前,不会转行
    • 职业规划随兴趣走
  • 肉身翻墙

    • 出去走一遭,趁年轻(工作或打工旅行)
    • 去牛逼公司镀金
  • 终极目标

    • 年轻时,向往自由工作者的工作方式,能够养活自己的游行工作方式
    • 适当年纪收心回归平常心(保持感兴趣的工作即可)

设计规范交流

#Label的一些使用规范 - 杨志平

##动态适应字体大小

iOS系统自带的常见字体样式(字号及粗细等等)

  • UIFontTextStyleHeadline
  • UIFontTextStyleSubheadline
  • UIFontTextStyleBody
  • UIFontTextStyleFootnote
  • UIFontTextStyleCaption1
  • UIFontTextStyleCaption2

###效果如下:

Font

代码

1
2
3
4
5
6
7
8
// 字体初始化
UIFont *font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
// 通知需要刷新的文本字体
[[NSNotificationCenter defaultCenter]addObserver:self
selector:@selector(userTextSizeDidChange)
name:UIContentSizeCategoryDidChangeNotification
object:nil];

国际化支持(适配注意点)

####工具:genstrings

####参考:博客链接

1
2
3
先看看它的宏定义:
#define NSLocalizedString(key, comment)
[[NSBundle mainBundle] localizedStringForKey:(key) value:@"" table:nil]

本地化对象:标签和按钮上的文本,或者在运行时获取的字符串和数据动态生成的字符串。

难点

不同语言的语法问题

语序,人称不一致:
「Paul invited you」和「You invited Paul」 -> 「%@ invited %@」,看似可以
以德语为例,「Paul invited you」译为「Paul hat dich eingeladen」,
而「You invited Paul」则译为「Du hast Paul eingeladen」。
正确处理其他语言的特殊语法方案:「%@ invited you」和「You invited %@」。

一词多意

1
2
3
4
5
6
7
8
run ->
vt. & vi. 跑
移动
(使)流动
n. 跑, 奔跑
旅行, 旅程
行驶路线
时期; 一段时间

正确做法:

1
2
NSLocalizedString(@"activity-profile.title.the-run", nil)
NSLocalizedString(@"home.button.start-run", nil)

或者:(完全没有试过)

NSLocalizedString 有一些变体能够提供更多字符串本地化的操作方式。NSLocalizedStringFromTable 接收 key、table 和 comment 这三个参数,其中 table 参数表示该字符串对应的一个表格,genstrings 会为表中的每一个条目生成一个以条目名称(假设为 table-item)命名的独立字符串文件 table-item.strings。
这样你就可以把字符串文件分割成几个小一些的文件。在一个庞大的项目或者团队中工作时,这一点显得尤为重要。同时这也让合并原有的和重新生成的字符串文件变得容易一些。

1
NSLocalizedStringFromTable(@"home.button.start-run", @"ActivityTracker", @"some comment..")

###调试本地化字符串(拓展)
应用支持的语言版本越多,确保所有元素都正确显示就越难。但是这里有一些默认的用户选项和工具可以减轻你的负担。

NSDoubleLocalizedStrings
AppleTextDirection
NSForceRightToLeftWritingDirection
选项保证你的布局不会因为长字符串或者从右往左读的语言而混乱。

NSShowNonLocalizedStrings
NSShowNonLocalizableStrings
则可以帮助你找到没有翻译的字符串和根本没有制定字符串本地化宏的字符串。

浅拷贝与深拷贝

浅拷贝与深拷贝

程序中经常会遇到集合类的传值

坑: 数组操作时对于数组中的对象拷贝

###目的:
观察array1、mArrayCopy、mArrayCopy2 三者区别

1
2
3
NSArray *array1 = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil];
NSArray *mArrayCopy = [[NSArray alloc] initWithArray:array1 copyItems:YES];
NSArray* mArrayCopy2 = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject: array1]];

首先了解copy与retain的区别

OC对象引用计数器:屋里开灯规则

copy是创建一个新对象,retain是创建一个指针,引用对象计数加1。Copy属性表示两个对象内容相同,新的对象retain为1 ,与旧有对象的引用计数无关,旧有对象没有变化。

retain属性表示两个对象地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的retain值+1也就是说,retain 是指针拷贝,copy 是内容拷贝。

主角:copy、mutableCopy

注意:可变和不可变对象使用copy、mutableCopy的区别

遵守NSCopying 协议的类可以发送copy消息,
遵守NSMutableCopying 协议的类才可以发送mutableCopy消息。

默认的ios类并没有遵守这两个协议
自定义copy 必须遵守NSCopying,并且实现 copyWithZone: 方法
自定义mutableCopy 那么就必须遵守NSMutableCopying,并且实现 mutableCopyWithZone: 方法

实例

系统的非容器类对象

这里指的是NSString,NSNumber等等一类的对象。

示例1:
不可变string

1
2
3
4
5
6
7
8
9
10
NSString *string = @"origionStr";
NSString *string2 = string;
NSString *stringCopy = [string copy];
NSMutableString *stringMCopy = [string mutableCopy];
[stringMCopy appendString:@"!!!!"];
// log
NSLog(@"string = %p %p %@ ",string,&string,string);
NSLog(@"string2 = %p %p %@ ",string2,&string2,string2);
NSLog(@"stringCopy = %p %p %@ ",stringCopy,&stringCopy,stringCopy);
NSLog(@"stringMCopy = %p %p %@ ",stringMCopy,&stringMCopy,stringMCopy);

结果:

1
2
3
4
string = 0x1064e7088 0x7fff597190a0 origionStr
string2 = 0x1064e7088 0x7fff59719098 origionStr
stringCopy = 0x1064e7088 0x7fff59719090 origionStr
stringMCopy = 0x7fafebdbb4b0 0x7fff59719088 origionStr!!!!

示例2:
可变string

1
2
3
4
5
6
7
8
9
10
NSMutableString *string = [NSMutableString stringWithString: @"origion"];
NSString *stringCopy = [string copy];
NSMutableString *mStringCopy = [string copy];
NSMutableString *stringMCopy = [string mutableCopy];
[string appendString:@" origion!"];
[stringMCopy appendString:@"!!"];
NSLog(@"string = %p %@",string,string);
NSLog(@"stringCopy = %p %@",stringCopy,stringCopy);
NSLog(@"stringMCopy = %p %@",mStringCopy,mStringCopy);
NSLog(@"stringMCopy = %p %@",stringMCopy,stringMCopy);

结果:

1
2
3
4
string = 0x7fafebdec820 origion origion!
stringCopy = 0x7fafebdcb8c0 origion
stringMCopy = 0x7fafebda4320 origion
stringMCopy = 0x7fafebd32890 origion!!

对于系统的非容器类对象,我们可以认为,如果对一不可变对象复制,copy是指针复制(浅拷贝)和mutableCopy就是对象复制(深拷贝)。如果是对可变对象复制,都是深拷贝,但是copy返回的对象是不可变的。

系统的容器类对象

指NSArray,NSSet,NSDictionary等。对于容器类本身,上面讨论的结论也是适用的,需要探讨的是复制后容器内对象的变化。

示例1:
不可变数组

1
2
3
4
5
6
7
8
9
10
//copy返回不可变对象,mutablecopy返回可变对象
NSArray *array1 = [NSArray arrayWithObjects:@"a",@"b",@"c",nil];
NSArray *arrayCopy1 = [array1 copy];
NSMutableArray *mArrayCopy1 = [array1 mutableCopy];
[mArrayCopy1 addObject:@"de"];
[mArrayCopy1 removeObjectAtIndex:0];
// log
NSLog(@"array1 = %p %@ %p %@",array1,array1,array1[1],array1[1]);
NSLog(@"arrayCopy1 = %p %@ %p %@",arrayCopy1,arrayCopy1,arrayCopy1[1],arrayCopy1[1]);
NSLog(@"mArrayCopy1 = %p %@ %p %@",mArrayCopy1,mArrayCopy1,mArrayCopy1[0],mArrayCopy1[0]);

结果:

1
2
3
array1 = 0x7fafebdeaed0 (a,b,c) 0x1064e7228 b
arrayCopy1 = 0x7fafebdeaed0 (a,b,c) 0x1064e7228 b
mArrayCopy1 = 0x7fafebdfc010 (b,c,de) 0x1064e7228 b

示例:
可变数组

1
2
3
4
NSArray *array1 = [NSArray arrayWithObjects:@"a",@"b",@"c",nil];
NSMutableArray *mArrayCopy = [[NSMutableArray alloc] initWithArray:array1 copyItems:YES];
NSLog(@"array1 = %p %@ %p %@ %p %@",array1, array1, array1[0], array1[0], array1[1], array1[1]);
NSLog(@"arrayCopy1 = %p %@ %p %@ %p %@",mArrayCopy,mArrayCopy, mArrayCopy[0], mArrayCopy[0], mArrayCopy[1], mArrayCopy[1]);

结果:

1
2
array1 = 0x7fafebcb5ae0 (a,b,c) 0x10afe1208 a 0x10afe1228 b
arrayCopy1 = 0x7fafebcb5b10 (a,b,c) 0x10afe1208 a 0x10afe1228 b

示例2:

1
2
3
NSArray *array1 = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil];
NSMutableArray *mArrayCopy = [[NSMutableArray alloc] initWithArray:array1 copyItems:YES];
NSArray* mArrayCopy2 = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject: array1]];

mArrayCopy2是完全意义上的深拷贝,而mArrayCopy则不是

对于mArrayCopy内的不可变元素其还是指针复制。或者我们自己实现深拷贝的方法。因为如果容器的某一元素是不可变的,那你复制完后该对象仍旧是不能改变的,因此只需要指针复制即可。除非你对容器内的元素重新赋值,否则指针复制即已足够。

那些年我们用过的第三方库

SnapKit(Masonry) 的使用 - 杨志平

这两个库的用法都是差不多的,只是由两个不同的人来主导开源

SnapKit是Swift版

Masonry是OC版

自动布局及交互式编程是iOS开发的趋势,同时Swift也会在不久将来替换OC语言。所以现在的iOS开发者可以开始学习Swift2.0 以及应用 Autolayout 来编程

代码对比(概况了解)

开始前OC原生布局代码
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
40
41
42
43
44
45
UIView *superview = self;
UIView *view1 = [[UIView alloc] init];
view1.translatesAutoresizingMaskIntoConstraints = NO;
view1.backgroundColor = [UIColor greenColor];
[superview addSubview:view1];
UIEdgeInsets padding = UIEdgeInsetsMake(10, 10, 10, 10);
[superview addConstraints:@[
//view1 constraints
[NSLayoutConstraint constraintWithItem:view1
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:padding.top],
[NSLayoutConstraint constraintWithItem:view1
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:padding.left],
[NSLayoutConstraint constraintWithItem:view1
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:-padding.bottom],
[NSLayoutConstraint constraintWithItem:view1
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeRight
multiplier:1
constant:-padding.right],
]];
使用Masonry

精简

1
2
3
4
5
6
7
8
9
UIEdgeInsets padding = UIEdgeInsetsMake(10, 10, 10, 10);
[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(superview.mas_top).with.offset(padding.top); //with is an optional semantic filler
make.left.equalTo(superview.mas_left).with.offset(padding.left);
make.bottom.equalTo(superview.mas_bottom).with.offset(- padding.bottom);
make.right.equalTo(superview.mas_right).with.offset(-padding.right);
}];

更加精简

1
2
3
[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(superview).with.insets(padding);
}];
同理使用SnapKit

精简

1
2
3
4
5
6
7
8
9
10
let box = UIView()
superview.addSubview(box)
box.snp_makeConstraints { (make) -> Void in
make.top.equalTo(superview).offset(20)
make.left.equalTo(superview).offset(20)
make.bottom.equalTo(superview).offset(-20)
make.right.equalTo(superview).offset(-20)
}

更加精简

1
2
3
box.snp_makeConstraints { (make) -> Void in
make.edges.equalTo(superview).inset(UIEdgeInsetsMake(20, 20, 20, 20))
}

如何使用 && 原理

常见的约束类型对比

ViewAttribute NSLayoutAttribute
view.snp_left NSLayoutAttribute.Left
view.snp_right NSLayoutAttribute.Right
view.snp_top NSLayoutAttribute.Top
view.snp_bottom NSLayoutAttribute.Bottom
view.snp_leading NSLayoutAttribute.Leading
view.snp_trailing NSLayoutAttribute.Trailing
view.snp_width NSLayoutAttribute.Width
view.snp_height NSLayoutAttribute.Height
view.snp_centerX NSLayoutAttribute.CenterX
view.snp_centerY NSLayoutAttribute.CenterY
view.snp_baseline NSLayoutAttribute.Baseline

常见的用法

1
2
3
4
5
6
7
8
9
10
make.top.equalTo(42)
make.lessThanOrEqualTo.equalTo(SuperView)
make.top.equalTo(SuperView)
make.size.equalTo(CGSizeMake(50, 100))
make.edges.equalTo(UIEdgeInsetsMake(10, 0, 10, 0))
make.left.equalTo(view).offset(UIEdgeInsetsMake(10, 0, 10, 0))
make.height.equalTo(OtherView).offset(10)
make.trailing.equalTo(OtherView.snp_trailing).offset(10)
make.bottom.equalTo(-20).priority(250)

对比交互式编程的约束布局

image