作者: xiao, yanzi

iOS CPU占有率达到了100%甚至更多,然后导致App闪退情况总结及解决过程

今天在真机调试的过程中,发现了一个严重的问题,发现CPU的使用率竟然达到了100%,以至于会导致运行内存占用过高,被系统的看门狗机制给杀掉。

下面就讲一讲怎么去定位这个问题:

1.打开Xcode,把项目跑动起来,然后选择这个选项卡

%title插图%num

2.现在就可以看到这个画面

%title插图%num
3. 现在我们可以看到这个页面,发现我的CPU达到了 105%,这肯定是有问题,那现在怎么办呢,我们可以看到右边的图,点击Profile in Instruments. —》 然后点击Transfer.

%title插图%num

4. 现在就进入到Instruments中,我们看看究竟发生了什么,到底是什么情况,导致出现了这种问题。

1. 首先,我通过观察CPU占用率,各个页面进行排查,看是进行了何种操作后,才出现的这种CPU占用率居高不小。

2. 我很庆幸,我很快就定位到了原因。所以我可以知道是进入某一个页面,触发了某种操作后,然后,就会出现这种情况

3. 现在就可以通过Instruments来进行定位,来看看是执行什么代码,导致了这种非常耗时的操作,让CPU一直如此忙碌。

4.选中Xcode先把程序(command + R)运行起来

5.再选中Xcode,按快捷键(command + control + i)运行起来,此时Leaks已经跑起来了

6.由于Leaks是动态监测,所以我们需要手动操作APP,一边操作,一边观察Leaks的变化,当出现红色叉时,就监测到了内存泄露,点击右上角的第二个,进行暂停检测(也可继续检测,当多个时暂停,一次处理了多个).

扩展: 查内存泄露具体方法 点击打开链接l

5. 电脑卡爆了,哎。 回去了在截图,反正*后是跟踪到了 Runloop下。 有一个行为一直在占据着主线程,并且不释放,所以导致CPU一直在大量消耗,内存也慢慢渐长,一般能造成这种情况的就只有循环,并且一直没有释放,我利用Instruments中的leaks,然后进行了各种各样的内存泄露的检测及修复, 也正是这样,我发现了问题的所在。 原来是我写的有一个方法有问题。 我写的代码如下:

我们很清晰的看到如果条件为真,这就是一个死循环,我的PM那时候,这儿就想做一个图片一直闪烁的效果,这儿可以采用三种方案,一种是用这种循环引用来执行一套方法, 一种是通过NSTimer来定时去调用一个方法。我开始选择了前者,那时候也知道后果,也许这个死循环会一直存在下去,直到这个VC被dealloc,*后一种是通过 core animation来实现。 这种事*推荐的,具体写法,我会在后面开博客进行讲解

-(void)animationAction:(bool)isNeedbreak{
if(!isNeedbreak) {
[self performSelector:@selector(animationAction:) withObject: [NSNumber numberWithBool:YES] afterDelay:2];
}
}
2. 由于有上面这个担心所以,我在popviewcontroller, 控制器出栈的时候,我调用了如下方法,那个时候太粗心了,大概比方,是我想延迟2s执行一个方法,这个过程中,我想终止方法,那就只有通过调用下面两种随意一种,我却很天真的以为,这样就可以完美的终止死循环的调用。

//这个是取消所有的延迟执行函数。
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(animationAction:) object:[NSNumber numberWithBool:YES]];
[NSObject cancelPreviousPerformRequestsWithTarget:self];

3. 发现问题依然存在,所以只能用我的第二种解决办法, 用NSTimer来代替他。代码如下

NSTimer *animationTwoTime = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(productBrandIconAnimationWithIsBreak:) userInfo:[NSNumber numberWithBool:NO] repeats:YES];

4. 然后在vc出栈的时候,然后把NSTimer进行 invalidate下。

总结:

1.以后一定要慎用用for循环来进行实现动画的连续执行.
2. 这种动画效果尽量用 core animation来进行解决。

 

iOS – Shell 脚本学习入门

解释器与编译器
1. 编译器过程:  源代码 – 预处理器 – 编译器 – 目标代码 – 链接器 – 可执行程序

2. 解释器过程:  源代码 – 解释器  (python ,shell , js)

 

如何学习脚本: 三步骤
1. 学语法

2. 看脚本

3. 抄

 

基本语法:省略 。 自己去 w3c学习 。

常用语法记录:

#!/bin/bash

IS_ZSH=””
# bash-3.2 和 zsh

: << !
Shebang(Hashbang):一个由井号和叹号构成的字符序列#!出现在文本文件的*行的前两个字符。
操作系统的程序加载器会分析Shebang后的内容,将这些内容作为解释器指令。
并调用该指令,并将载有Shebang的文件路径作为该解释器的参数。

#!/usr/bin/python

#!/usr/bin/env pyhon

env:不同对操作系统,脚本解释器可能被安装于系统的不同的目录,设置到系统的PATH中。
env可以在系统的PATH目录中查找。
上述命令,使用在用户路径中找到的*个Python版本。但是可以通过指定版本号:
#!/usr/bin/env pythonX.x

env也可以指定搜索目录:
#!/usr/bin/env -S -P/usr/local/bin:/usr/bin:${PATH} python
会在/usr/local/bin、/usr/bin、系统PATH搜索python。
!

# echo “单行注释”

: << !
多行注释方式一:
echo “多行注释”
!

: << COMMENT
多行注释方式二:
echo “多行注释”
COMMENT

: ‘
多行注释方式三:
echo “多行注释”

if false; then
多行注释方式四:
echo “多行注释”
fi

((0)) && {
多行注释方式五:
echo “多行注释”
}

# 有空格时,将串包裹起来
VARIABLE=”Some string”
LUE=VARIABLE
# FOO=””
LONG_STRING=”I am Cat\\”
LONG_LONG_STRING=”I am Cat!CAT!Cat!Cat”

: ‘COMMENT
单引号与双引号,括号一定要成对
冒号(:)作为内建命令:占位符、参数扩展和重定向
子进程:在当前的shell下,去打开另一个新shell
env:查看环境变量与常见环境变量说明

PS1:提示符设置 [\u@\h \w \A #\#]\$
1. \h 主机名缩写
2. \u 用户账号名称
3. \w 完整工作路径
4. \A 24小时时间
5. \# 第几个命令
6. \$ 提示符,如果是root,提示符为#,否则是$
HOME:代表用户主文件夹。
SHELL:当前使用的是那个SHELL
PATH:执行文件查找路径
export: 自定义变量转环境变量
locale:显示语系变量
read [-pt] 变量 读取键盘变量
-p:提示符
-t:等待秒数

$(( 20 + 5 * 6)):返回双括号内算数运算的结果。
expr命令是一款表达式计算工具,使用它完成表达式的求值操作。
eval会对后面的cmdLine进行两遍扫描,如果*遍扫描后,cmdLine是个普通命令,则执行此命令;
如果cmdLine中含有变量的间接引用,则保证间接引用的语义。
type:显示命令属性,不加参数时,会显示该命令是内置命令还是其他。
-t:显示命令属性缩写
file:代表外部命令。
alias:代表该命令为别名。
builtin:内置命令。
-p:为外部命令时,会显示命令所在的文件
-a:将PATH中设置的所有的与命令名相关的列出来
echo [-ne][字符串]
-n 不要在*后自动换行
-e 若字符串中出现以下字符,则特别加以处理
\a 发出警告;
\b 删除前一个字符;
\c 不产生进一步输出 (\c 后面的字符不会输出);
\f 换行但光标仍旧停留在原来的位置;
\n 换行且光标移至行首;
\r 光标移至行首,但不换行;
\t 插入tab;
\v 与\f相同;
\\ 插入\字符;
\nnn 插入 nnn(八进制)所代表的ASCII字符;
用echo命令打印带有色彩的文字:
文字色:
echo -e “\e[1;31mThis is red text\e[0m”
\e[1;31m 将颜色设置为红色
\e[0m 将颜色重新置回
颜色码:重置=0,黑色=30,红色=31,绿色=32,黄色=33,蓝色=34,洋红=35,青色=36,白色=37
背景色:
echo -e “\e[1;42mGreed Background\e[0m”
颜色码:重置=0,黑色=40,红色=41,绿色=42,黄色=43,蓝色=44,洋红=45,青色=46,白色=47
文字闪动:
echo -e “\033[37;31;5mMySQL Server Stop…\033[39;49;0m”
红色数字处还有其他数字参数:0 关闭所有属性、1 设置高亮度(加粗)、4 下划线、5 闪烁、7 反显、8 消隐
COMMENT’

#
# if [ true ]; then
# :
# fi

#${VAR:=DEFAULT}
: ${VAR:=DEFAULT}
echo $VAR

: ‘COMMENT
1. Shell变量默认为字符串。shell不关心这个串是什么含义。
2. Shell默认的数值运算是整数类型。所以若要进行数学运算,必须使用一些命令例如declare、expr、双括号等。
3. Shell变量可分为两类:
i. 局部变量:只在创建它们的shell中可用。在函数内定义,函数执行后就被删除。
ii. 环境变量:可以在创建它们的shell及其派生出来的任意子进程中使用。在整个脚本执行期间,只要没有被删除就一直存在。
3. 定义规则:变量名必须以字母或下划线字符开头。其余的字符可以是字母、数字(0~9)或下划线字符。任何其他的字符都标志着变量名的终止。
小写敏感。
4. 给变量赋值时,等号周围不能有任何空白符。
5. 通常大写字符为系统默认变量。个人习惯。
6. set:查看所有变量(含环境变量与自定义变量),以及设置shell变量的新变量值。
-a:标示已修改的变量,以供输出至环境变量。
-b:使被中止的后台程序立刻回报执行状态。
-e:若指令传回值不等于0,则立即退出shell。
-f:取消使用通配符。
-h:自动记录函数的所在位置。
-H Shell:可利用”!”加<指令编号>的方式来执行history中记录的指令。
-k:指令所给的参数都会被视为此指令的环境变量。
-l:记录for循环的变量名称。
-m:使用监视模式。
-n:只读取指令,而不实际执行。
-p:启动优先顺序模式。
-P:启动-P参数后,执行指令时,会以实际的文件或目录来取代符号连接。
-t:执行完随后的指令,即退出shell。
-u:当执行时使用到未定义过的变量,则显示错误信息。
-v:显示shell所读取的输入值。
-x:执行指令后,会先显示该指令及所下的参数。
7. declare/typeset [-aixrp] 变量
-a 将变量定义成数组
-i 将变量定义成整数
-x 将变量定义成环境变量
-r 将变量定义成readonly
-p:显示变量定义的方式和值
+:取消变量属性,但是 +a 和 +r 无效,无法删除数组和只读属性,可以使用unset删除数组,但是 unset 不能删除只读变量。
8. local关键字,用来在作用域内创建变量。出来作用域被销毁。
9. export为shell变量或函数设置导出属性,成为环境变量。无法对未定义的函数添加导出属性。同时,重要的一点是,export的效力仅及于该次登陆操作。
注销或者重新开一个窗口,export命令给出的环境变量都不存在了。
-f:代表[变量名称]为函数名称。。
-n:删除变量的导出属性。变量实际上并未删除,只是不会输出到后续指令的执行环境中。
-p:显示全部拥有导出属性的变量。
-pf:显示全部拥有导出属性的函数。
-nf:删除函数的导出属性。
–:在它之后的选项无效。
10. 通配符
*:匹配任意字符串,包括空字符串,不包含对“/”字符的匹配。
?:匹配任意单个字符,不能匹配“/”字符。
[abc]:匹配“a”或者“b”或者“c”字符。
[^abc]:不匹配“a”或者“b”或者“c”字符。
[a-z]:匹配26个英文小写字符中任意一个。
用set命令可以查看所有的变量,unset var命令可以清除变量var,var相当于没有定义过。
readonly var可以把var变为只读变量,定义之后不能对var进行任何更改。

COMMENT’

if [[ -n $IS_ZSH ]]; then
# 根据变量属性强制转换值的英文大小写。
declare -u uc_var=’abc’
declare -l lc_var=’ABC’
# 显示’ABC abc’;
echo “${uc_var} ${lc_var}”
fi

# 执行后显示7,注意空格。
# expr 3 + 4
# result=`expr 2 + 3`
# echo $result

# # 没有指定整型属性,输出为字符串’a+b’。
# declare a=3 b=4 c
# c=a+b
# # a+b
# echo ${c}
# declare -p a

# # 不过可以使用以下方式赋值。
# c=$((a+b))
# # 7
# echo ${c}

# 设置了整型属性就可以直接加了。
# declare -i a=3 b=4 c
# c=a+b
# # 7
# echo ${c}
# declare -p a

# declare -p VARIABLE

# # 定义函数内的全局变量
# function test() {
# declare testA=3
# VARIABLE=”Value”
# local testB=3
# # 让我们查看它们的属性。
# declare -p testA VARIABLE testB
# }
# # 执行函数。
# test
# #Value
# echo $testA $VARIABLE $testB

# export a b=3
# # 当然也可以先定义后增加导出属性
# export VARIABLE
# 删除变量的导出属性
# export -n a b
# function func_1(){ echo ‘123’; }
# # 为已定义函数增加导出属性
# export -f func_1
# # 删除函数的导出属性
# export -fn func_1

# set 11 22 33 44
# # 44
# echo $4
# # $4
# echo “\$$#”
# # 44 *遍得到变量个数4,第二遍去第四个
# eval echo “\$$#”

# declare mylove=’Cat’ #定义新变量
# # env | grep mylove mylove=Cat
# set -a mylove #设置为环境变量

# echo “./*.sh”
# echo “./*”.sh
# MMM=`echo “./*.sh”`
# echo $MMM
# echo `echo “./*.sh”`
# echo ./*.sh
# set — “./”*.sh
# echo “$1″

: ‘COMMENT
数组:
var[1]=”var1”
var[2]=1
COMMENT’

# source Shell.sh
export VARIABLE

unset VARIABLE
echo $VARIABLE

: ‘COMMENT
运行方式:
1. sh:
使用$ sh script.sh执行脚本时,当前shell是父进程,生成一个子shell进程,在子shell中执行脚本。
脚本执行完毕,退出子shell,回到当前shell。$ ./script.sh与$ sh script.sh等效。
2. source:
使用$ source script.sh方式,在当前上下文中执行脚本,不会生成新的进程。脚本执行完毕,回到当前shell。
$ . script.sh与$ source script.sh等效。
3. exec方式:
使用exec command方式,会用command进程替换当前shell进程,并且保持PID不变。
执行完毕,直接退出,不回到之前的shell环境。
COMMENT’

: ‘COMMENT
参数扩展:通过符号$获得参数中存储的值。
1. 间接参数扩展${!parameter},,zsh不支持
i. ${parameter-string}:当parameter未设置则替换成string,不更改parameter值。否则,不做处理。
ii. ${parameter=string}:当parameter未设置则替换成string,更改parameter值。否则,不做处理。
iii. ${parameter?string}:parameter没有设置,则把string输出到标准错误中。否则,不做处理。
iiii. ${parameter+string}:当parameter为空的时替换成string。否则,不做处理。
2. 冒号后面跟 等号,加号,减号,问号(⚠不能有空格):
i. ${parameter:-string}:当parameter未设置或者为空则替换成string,不更改parameter值。
ii. ${parameter:=string}:当parameter未设置或者为空则替换成string,更改parameter值。
iii. ${parameter:?string}:若变量parameter不为空,则使用变量parameter的值。
若为空,则把string输出到标准错误中,并从脚本中退出。
iiii. ${parameter:+string}:当parameter不为空的时替换成string。若为空时则不替换或者说是替换空值。
3. 子串扩展:${parameter:offset}和${parameter:offset:length}。
从offset位置开始截取长度为length的子串,如果没有提供length,则是从offset开始到结尾。
i. offset可以是负值,且必须与冒号有间隔或者用()包裹。开始位置是从字符串末尾开始算起,然后取长度为length的子串。
例如,-1代表是从*后一个字符开始。
ii. parameter是@,也就是所有的位置参数时,offset必须从1开始。
4. 替换:${parameter/pattern/string}、${parameter//pattern/string}、${parameter/pattern}和${parameter//pattern}。
大小写敏感。string为空时,则相当于将匹配的子串删除。 parameter之后如果是/,则只匹配遇到的*个子串;
parameter之后如果是//,则匹配所有的子串。
5. 删除:${parameter#pattern}、${parameter##pattern}、${parameter%pattern}和${parameter%%pattern}。
i. # 是去掉左边,% 是去掉右边。单一符号是*小匹配﹔两个符号是*大匹配。
6. 参数长度:${#parameter}
COMMENT’

: ‘COMMENT
标准输入(stdin):代码为0,使用<或<<;
标准输出(stdout):代码为1,使用>或>>;
标准错误输出(stderr):代码为2,使用2>或2>>;
1> 以覆盖的方式将正确的数据输出到指定到文件或设备;
1>> 以累加到方法将正确到数据输出到指定到文件或者设备上;
2> 以覆盖的方式将错误的数据输出到指定到文件或设备;
2>> 以累加的方式将错误的数据输出到指定到文件或设备;
2>/dev/null 将错误到数据丢弃,只显示正确到数据
2>&1 或者 &>将正确到数据和错误到数据写入同一个文件
cmd;cmd 不考虑命令相关性,连续执行。
当前一个命令执行成功会回传一个 $?=0的值。
cmd1 && cmd2 如果*个命令的$?为0,则执行第二个命令。
cmd1 || cmd2 如果*个命令的$?为0,则不执行第二个命令。否则执行第二个命令。
|:管道仅能处理前面一个命令传来的正确信息,将正确信息作为stdin传给下一个命令
– :stdin和stdout利用减号“-“来代替
COMMENT’

: ‘COMMENT
sh [-nvx] scripts.h
-n:不执行,仅检查语法。
-v:在执行脚本之前,先将脚本内容输出。
-x:将使用到的脚本内容,输出。
COMMENT’

: ‘COMMENT
当条件成立,就进行循环:
while [ condation ] #判断条件
do #循环开始
程序
done #循环结束
当条件成立,就终止循环:
until [ condation ] #判断条件
do #循环开始
程序
done #循环结束
按照指定次数循环:
for var in con1 con2 con3 …
do
程序
done
for (( 初始值; 限制值; 执行步长 ))
do
程序
done
COMMENT’

: ‘COMMENT
多分支语句判断
除*后一个分支外(这个分支可以是普通分支,也可以是*)分支),其它的每个分支都必须以;;结尾,;;代表一个分支的结束,不写的话会有语法错误。
*后一个分支可以写;;,也可以不写,因为无论如何,执行到 esac 都会结束整个 case in 语句。
case $变量 in
“*个变量内容”)
程序
;; #结束
*) # 用来托底,没有匹配到数据
;;
esac
COMMENT’

: ‘COMMENT
一个条件判断:
if [ condation ]; then
成立
else
不成立
fi
多条件判断:
if [ condation ]; then
成立
elif [ condation ]; then
成立
else
不成立
fi
COMMENT’

: ‘COMMENT
shift:参数号码偏移。会移动变量,可以接数字,代表移动前面几个参数的意思
COMMENT’

: ‘COMMENT
[]:判断符号,两个等号和一个等号,效果类似。
1. 中括号里面的每个组件都需要空格分隔。
2. 中括号的变量,使用双引号
3. 中括号的常量,使用单引号或双引号
COMMENT’

: ‘COMMENT
test命令测试:
1. test n1 -eq n2:
-eq:相等
-ne:不等
-gt:大于
-lt:小于
-ge:大于等于
-le:小于等于
2. 字符串判断
-z string:判断string是否为0,为空,则为true。
-n string:判断string是否非0,为空,则为false。
string1 = string2:字符串是否相等,相等为true。
string1 != string2:字符串是否不等,相等为false。
3. 多重条件判断
-a:两个条件同时成立,为true。
-o:两个条件任何一个成立,为true。
!:反向。
4. 文件类型判断
-e:文件名是否存在。
-f:该文件名是否存在且是否为文件。
-d:该名称是否存在且为目录。
-L:该名称是否存在且是否为链接文件。
5. 文件权限检测
-r:是否存在是否有可读权限。
-w:是否存在是否有可写权限。
-x:是否存在是否有可执行权限。
-s:是否存在且为非空白文件。
6. 两文件比较
-nt 文件1是否比文件2新。
-ot 文件1是否比文件2旧。
-ef 文件1和文件2是否为同一个文件。
COMMENT’

# # Some string
# echo “${!VALUE}”

# #
# echo “${FOO-“Cat-“}”
# # Cat-
# echo “${FOO=”Cat-“}”
# #
# echo “${FOO+”Cat-“}”
# # Cat-
# echo “${FOO?”Cat—-“}”

# # Cat-
# echo “${FOO:-“Cat-“}”
# # Cat=
# echo “${FOO:=”Cat=”}”
# # Cat=
# echo “${FOO:?”Cat?”}”
# #Cat+
# echo “${FOO:+”Cat+”}”

# #Cat\
# echo “${LONG_STRING:5}”
# #Cat
# echo “${LONG_STRING:5:3}”
# #Cat
# echo “${LONG_STRING: -4:3}”
# #Cat
# echo “${LONG_STRING: -4:3}”
# #Cat
# echo “${LONG_STRING:(-4):3}”

# # I am Cat!CAT!Cat!Cat
# echo “${LONG_LONG_STRING/cat}”
# # I am LGCat!CAT!LGCat!LGCat
# echo “${LONG_LONG_STRING//Cat/LGCat}”

# # am Cat!CAT!Cat!Cat
# echo “${LONG_LONG_STRING#* }”
# # am Cat!CAT!Cat!Cat
# echo “${LONG_LONG_STRING#? }”

# # at!CAT!Cat!Cat
# echo “${LONG_LONG_STRING#*[Cc]}”

# if [[ -n $IS_ZSH ]]; then
# # Cat!CAT!Cat!Cat
# echo “${LONG_LONG_STRING#*(AT|m)}”
# echo “—–${LONG_LONG_STRING#*(AT|m)}”
# echo “—–${LONG_LONG_STRING#[A-z]**(AT|m)}”
# # !Cat!Cat
# echo “—–${LONG_LONG_STRING#*(AT|mm)}”
# fi

# # m Cat!CAT!Cat!Cat
# echo “${LONG_LONG_STRING#*[a-t]}”
# # m Cat!CAT!Cat!Cat
# echo “${LONG_LONG_STRING#*[a-t]}”
# # am Cat!CAT!Cat!Cat
# echo “${LONG_LONG_STRING#*[^A-Z]}”

# echo `echo “./*.sh”`
# echo `echo “./”*.sh`

# # Cat!CAT!Cat!Cat
# echo “${LONG_LONG_STRING##* }”
# # at
# echo “${LONG_LONG_STRING##*[Cc]}”
# #
# echo “${LONG_LONG_STRING##*[a-t]}”

# # I am
# echo “${LONG_LONG_STRING% *}”
# # I
# echo “${LONG_LONG_STRING%% *}”

# # 20
# echo “${#LONG_LONG_STRING}”

# # i am cat!cat!cat!cat
# echo “$(echo “${LONG_LONG_STRING}” | tr “[:upper:]” “[:lower:]”)”
# # I AM CAT!CAT!CAT!CAT
# echo “$(echo “${LONG_LONG_STRING}” | tr “[:lower:]” “[:upper:]”)”

# if [[ -n $IS_ZSH ]]; then
# # I AM CAT!CAT!CAT!CAT
# echo “${LONG_LONG_STRING:u}”
# # i am cat!cat!cat!cat
# echo “${LONG_LONG_STRING:l}”
# fi

# : ${TEM:=”./”*.sh}
: ‘COMMENT
函数的声明形式:
function 函数名 {
函数体
}
function 函数名() {
函数体
}
函数名() {
函数体
}
1. 有funtion,可以不写(),没有function,必须写()。
2. 函数名和”{“之间必须有空格。
3. 不得声明形式参数。
4. 必须在调用函数地方之前,声明函数
5. 无法重载
6. 后来的声明会覆盖之前的声明
7. 没有返回值的函数,默认返回函数内*后一条指令的返回值。有返回值的函数,只能返回整数。
8. 需要获得函数值,只能通过$?获得。通过=获得是空值。

我们可以将shell中函数,看作是定义一个新的命令,因此各个输入参数直接用空格分隔。
一次,命令里面获得参数方法可以通过:$0…$n得到。$0代表函数本身。
$#:传入的参数的个数。
$*:所有的位置参数(作为单个字符串)。
$@:所有的位置参数(每个都作为独立的字符串)。
$?:当前shell进程中,上一个命令的返回值,如果上一个命令成功执行则$?的值为0,否则为其他非零值。
$$:当前shell进程的pid。
$!:后台运行的*后一个进程的pid。
$-:显示shell使用的当前选项。
$_:之前命令的*后一个参数。
COMMENT’

# 无输出
# logic
# function DoWork {
# local LG_CAT=”LG_Cat”
# echo “logic”
# return 2
# }
# DoWork() {
# local LG_CAT=”LG_Cat”
# echo “logic”
# return 2
# }

# 无输出
# logic
# function DoWork {
# local LG_CAT=”LG_Cat”
# echo “logic”
# return 2
# }
# echo $LG_CAT
# echo `DoWork`
# 无输出
# logic
# function DoWork {
# LG_CAT=”LG_Cat”
# echo “logic”
# return 2
# }
# echo $LG_CAT
# echo `DoWork`
# logic
# 无输出
# function DoWork {
# LG_CAT=”LG_Cat”
# echo “logic”
# return 2
# }
# echo `DoWork`
# echo $LG_CAT
# logic
# logic
# LG_Cat
# function DoWork {
# LG_CAT=”LG_Cat”
# echo “logic”
# return 2
# }
# DoWork
# echo `DoWork`
# echo $LG_CAT
# logic
# 2
# logic
# 0
# function DoWork {
# LG_CAT=”LG_Cat”
# echo “logic”
# return 2
# }
# DoWork
# echo “$?”
# echo `DoWork`
# echo “$?”
# function DoWork {
# echo “特殊变量:\n
# \$#:$#\\n
# \$0:$0\\n
# \$1:$1\\n
# \$2:$2\\n
# \$*:$*\\n
# \$@:$@\\n
# \$$:$$\\n
# \$-:$-\\n
# \$_:$_
# ”
# return 2
# }
# DoWork “Cat” “LGCat”
array=($MMM 1 2)

echo $array

declare -p MMM

declare -p array
if [[ -n $IS_ZSH ]]; then
declare -A fruits=([‘apple’]=’red’ [‘banana’]=’yellow’)
# 显示所有关联数组。
declare -A
# red yellow
echo ${fruits[@]}
echo ${fruits[*]}
echo ${(@k)fruits}
fi

脚本实现:
while [[ $# -gt 0 ]]; do
case $1 in
-d|–directory)
shift
echo “$1—-”
shift
;;
-k|–keyword)
shift
echo “$1 —-”
shift
;;
-s|-source)
echo “$1 —-source”
shift
;;
-f|–framework)
shift
;;
-l|–lib)
shift
;;
-h|–help)
Show_Help
exit 0
;;
*)
echo “Unknown option: $1”
exit 1
esac
done
通过上面的脚本来学习脚本:

while do  case : 循环

[[ $# -gt 0 ]] :

$# ,获取执行脚本的时候传递的参数个数

-gt : 大于

$1: 循环的参数值

exit: 0 正常退出

其他exit: 为自定义意义。

 

自定义一个脚本说明文档

格式如下:

Show_Help() {
# 结束符
cat <<EOF

find_api.sh –directory <dir> 在指定目录指定文件内搜索指定关键字。

-d|–directory <dir> – 指定查找目录,默认当前所在目录
-k|–keyword <word> – 查找关键字
-s|–source – 指定查找源码文件
-f|–framework – 指定查找framework文件
-l|–lib – 指定查找libs文件
–help – prints help screen

EOF

}
注意EOF不要有空格。

cat <<EOF

中间写上脚本的使用文档

EOF

查找、细分查询功能
find . -name “*.framework”
find . -name “*.h” -exec echo {} \;
grep -E “some|weak” -A 1 -B 1 -i
nm -pa <mach-o>
find : 查找文件  -name ‘字串’  查找文件名匹配所给字串的所有文件,字串内可用通配符 *、?、[ ]。

grep: 搜索具体文件中的关键字   -E   –extended-regexp             # 将范本样式为延伸的普通表示法来使用,意味着使用能使用扩展正则表达式

 

数组与For循环
# <<< 表示将右侧的字符串传递到左侧命令的标准输入。
# < 将文件的内容传递到命令的标准输入
# << 将带有结束标志的文档内容传递到命令的标准输入

#test
#-e:文件名是否存在。
#-f:该文件名是否存在且是否为文件。
#-d:该名称是否存在且为目录。
#-L:该名称是否存在且是否为链接文件。

#read
#-a 后跟一个变量,该变量会被认为是个数组,然后给其赋值,默认是以空格为分割符。
#-r 屏蔽\,如果没有该选项,则\作为一个转义字符,有的话 \就是个正常的字符了。

# read通过输入重定向,把file的*行所有的内容赋值给变量line,循环体内的命令一般包含对变量line的处理;然后循环处理file的第二行、第三行。。。一直到file的*后一行。
#for是每次读取文件中一个以空格为分割符的字符串。
#for是每次读取字符串中一个以空格为分割符的字符串。
#weak|cat|Hank
Find_Api() {
local key_word=””
if [[ -n “${KEYWORD}” ]]; then
read -a names <<< “${KEYWORD}”
for name in ${names[@]}
do
if [[ ! -n “${key_word}” ]]; then
key_word=”$name”
else
key_word=”$key_word|$name”
fi
done
else
echo “请输入查找的关键字!”
exit 1
fi
echo “$key_word —-”
}
 

iOS开发之第三方登录微信– 史上*全*新第三方登录微信方式实现

*新版本的微信登录实现步骤实现:

1.在进行微信OAuth2.0授权登录接入之前,在微信开放平台注册开发者帐号,并拥有一个已审核通过的移动应用,并获得相应的AppID和AppSecret,申请微信登录且通过审核后,可开始接入流程。 地址: 点击打开链接

2. 下载*新的SDK   地址: 点击打开链接

%title插图%num

SDK内容如下:

%title插图%num

结构解析:

从上到下依次说明:

1. 静态库,直接拖入工程。

2. ready.text自己看

3. 授权SDK。

4. 登录方法所在类。

5.  一些常用的对象类。

iOS微信登录注意事项:

1、目前移动应用上微信登录只提供原生的登录方式,需要用户安装微信客户端才能配合使用。
2、对于Android应用,建议总是显示微信登录按钮,当用户手机没有安装微信客户端时,请引导用户下载安装微信客户端。
3、对于iOS应用,考虑到iOS应用商店审核指南中的相关规定,建议开发者接入微信登录时,先检测用户手机是否已安装微信客户端(使用sdk中isWXAppInstalled函数 ),对未安装的用户隐藏微信登录按钮,只提供其他登录方式(比如手机号注册登录、游客登录等)。

iOS微信登录大致流程:

1. 第三方发起微信授权登录请求,微信用户允许授权第三方应用后,微信会拉起应用或重定向到第三方网站,并且带上授权临时票据code参数;
2. 通过code参数加上AppID和AppSecret等,通过API换取access_token;
3. 通过access_token进行接口调用,获取用户基本数据资源或帮助用户实现基本操作。

示意图:

%title插图%num

接下来就进入正题:

1.配置工程
1. 新建一个工程。
2. 把下载下来的sdk中的.h文件与静态库全部拖入工程。
3.  加入依赖库

%title插图%num

4.  URL – Types  (加入 appid)
target  –  Info – URL Types
%title插图%num

5. 白名单
当程序出现此错误
-canOpenURL: failed for URL: “weixin://app/wx5efead4057f98bc0/” – error: “This app is not allowed to query for scheme weixin”
就说明没有针对iOS9 增加白名单。 在info.plist文件中加入 LSApplicationQueriesSchemes

App Transport Security 这个是让程序还是用http进行请求。
LSApplicationQueriesSchemes 这个是增加微信的白名单。

%title插图%num

6.  现在编译应该是没有问题了。

2. 终于到令人兴奋的代码部分了。 直接上代码。
//
// AppDelegate.m
// weixinLoginDemo
//
// Created by 张国荣 on 16/6/20.
// Copyright © 2016年 BateOrganization. All rights reserved.
//

#import “AppDelegate.h”
#import “WXApi.h”

//微信开发者ID
#define URL_APPID @”app id”

@end

@implementation AppDelegate

– (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

//向微信注册应用。
[WXApi registerApp:URL_APPID withDescription:@”wechat”];
return YES;
}

-(BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString *,id> *)options{

/*! @brief 处理微信通过URL启动App时传递的数据
*
* 需要在 application:openURL:sourceApplication:annotation:或者application:handleOpenURL中调用。
* @param url 微信启动第三方应用时传递过来的URL
* @param delegate WXApiDelegate对象,用来接收微信触发的消息。
* @return 成功返回YES,失败返回NO。
*/

return [WXApi handleOpenURL:url delegate:self];
}

/*! 微信回调,不管是登录还是分享成功与否,都是走这个方法 @brief 发送一个sendReq后,收到微信的回应
*
* 收到一个来自微信的处理结果。调用一次sendReq后会收到onResp。
* 可能收到的处理结果有SendMessageToWXResp、SendAuthResp等。
* @param resp具体的回应内容,是自动释放的
*/
-(void) onResp:(BaseResp*)resp{
NSLog(@”resp %d”,resp.errCode);

/*
enum WXErrCode {
WXSuccess = 0, 成功
WXErrCodeCommon = -1, 普通错误类型
WXErrCodeUserCancel = -2, 用户点击取消并返回
WXErrCodeSentFail = -3, 发送失败
WXErrCodeAuthDeny = -4, 授权失败
WXErrCodeUnsupport = -5, 微信不支持
};
*/
if ([resp isKindOfClass:[SendAuthResp class]]) { //授权登录的类。
if (resp.errCode == 0) { //成功。
//这里处理回调的方法 。 通过代理吧对应的登录消息传送过去。
if ([_wxDelegate respondsToSelector:@selector(loginSuccessByCode:)]) {
SendAuthResp *resp2 = (SendAuthResp *)resp;
[_wxDelegate loginSuccessByCode:resp2.code];
}
}else{ //失败
NSLog(@”error %@”,resp.errStr);
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@”登录失败” message:[NSString stringWithFormat:@”reason : %@”,resp.errStr] delegate:self cancelButtonTitle:@”取消” otherButtonTitles:@”确定”, nil];
[alert show];
}
}
}

@end
下面是登录的类。

//
// ViewController.m
// weixinLoginDemo
//
// Created by 张国荣 on 16/6/20.
// Copyright © 2016年 BateOrganization. All rights reserved.
//

#import “ViewController.h”
#import “WXApi.h”
#import “AppDelegate.h”
//微信开发者ID
#define URL_APPID @”appid”
#define URL_SECRET @”app secret”
#import “AFNetworking.h”
@interface ViewController ()<WXDelegate>
{
AppDelegate *appdelegate;
}
@end

@implementation ViewController

– (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
#pragma mark 微信登录
– (IBAction)weixinLoginAction:(id)sender {

if ([WXApi isWXAppInstalled]) {
SendAuthReq *req = [[SendAuthReq alloc]init];
req.scope = @”snsapi_userinfo”;
req.openID = URL_APPID;
req.state = @”1245″;
appdelegate = [UIApplication sharedApplication].delegate;
appdelegate.wxDelegate = self;

[WXApi sendReq:req];
}else{
//把微信登录的按钮隐藏掉。
}
}
#pragma mark 微信登录回调。
-(void)loginSuccessByCode:(NSString *)code{
NSLog(@”code %@”,code);
__weak typeof(*&self) weakSelf = self;

AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.requestSerializer = [AFJSONRequestSerializer serializer];//请求
manager.responseSerializer = [AFHTTPResponseSerializer serializer];//响应
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@”text/html”,@”application/json”, @”text/json”,@”text/plain”, nil];
//通过 appid secret 认证code . 来发送获取 access_token的请求
[manager GET:[NSString stringWithFormat:@”https://api.weixin.qq.com/sns/oauth2/access_token?appid=%@&secret=%@&code=%@&grant_type=authorization_code”,URL_APPID,URL_SECRET,code] parameters:nil progress:^(NSProgress * _Nonnull downloadProgress) {

} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { //获得access_token,然后根据access_token获取用户信息请求。

NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingMutableContainers error:nil];
NSLog(@”dic %@”,dic);

/*
access_token 接口调用凭证
expires_in access_token接口调用凭证超时时间,单位(秒)
refresh_token 用户刷新access_token
openid 授权用户唯一标识
scope 用户授权的作用域,使用逗号(,)分隔
unionid 当且仅当该移动应用已获得该用户的userinfo授权时,才会出现该字段
*/
NSString* accessToken=[dic valueForKey:@”access_token”];
NSString* openID=[dic valueForKey:@”openid”];
[weakSelf requestUserInfoByToken:accessToken andOpenid:openID];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@”error %@”,error.localizedFailureReason);
}];

}

-(void)requestUserInfoByToken:(NSString *)token andOpenid:(NSString *)openID{

AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
[manager GET:[NSString stringWithFormat:@”https://api.weixin.qq.com/sns/userinfo?access_token=%@&openid=%@”,token,openID] parameters:nil progress:^(NSProgress * _Nonnull downloadProgress) {

} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSDictionary *dic = (NSDictionary *)[NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingMutableContainers error:nil];
NSLog(@”dic ==== %@”,dic);

} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@”error %ld”,(long)error.code);
}];
}

– (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

@end

大功告成。

 

Mac系统上使用SnailSVN的配置步骤

1·在Apple Store下载SvnSnail: Lite版本(需输入apple id)
2·打开SnailSVN
3·点击General,打开系统设置(Open System Preference),勾上SnailSVNLite: Finder Extensions
4·点击SVN Settings,选择paths
5·创建.ssh路径,先打开终端Terminal,然后输入 mkdir .ssh,创建完成后就可以paths中选择你刚刚创建的.ssh,再依次选择bin以及Applications路径。/Users/xxx/.ssh, /urs/local/bin, /Applications
6·新建一个文件夹名为 svn-workspace 作为工作路径
7·点击SnailSVN Lite左上角的File->Svn Checkout,输入项目的svn地址,检出项目的路径到 svn-workspace,点击确定,弹出验证框,输入svn帐号密码即可。
8·结束

iOS 10.3 改进后的App Review机制

今天没事查看了下iOS 10.3 的变更功能。发现Apple修改了Review机制,提供App内直接Review弹窗。

SKStoreReviewController.requestReview()
%title插图%num

如果没有网络则无任何反应。
据说有调用次数限制,不过API中没有提到,我测试也没有触发这个现象。

看了API说明的话,有人可能注意到了,这句话:

available to the App Store by appending the query params “action=write-review” to a product URL.

我测试了下,如果在itms-apps url中添加action=write-review则可以打开AppStore中App评论详情,同时自动打开评论编辑窗口。

func reviewApp(for appId: String) {
if let url = URL(string: “itms-apps://itunes.apple.com/app/id\(appId)?action=write-review”) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
}

%title插图%num

Mac下的SVN客户端工具Cornerstone使用教程

使用命令当然是一个非常好的选择,但是对我们人类来说还是喜欢图形化界面的操作的。因此本文将介绍我喜欢的一款SVN客户端工具的使用。

 

想要安装的Cornerstone的朋友,我有个坏消息是,如果你想使用它的正版软件,你是需要花费几十美金的,当然这里我带给您的永远都是有价值的好的信息,那就是在我们天朝使用软件还花钱真的是*品,我就奉献一下我在网上找到的一个比较好的破解版:http://pan.baidu.com/s/1o6F31zG

 

这个破解版本的Cornerstone软件安装方法我就不做介绍了,因为太容易。本文重点介绍一下它的使用方法。

 

当你打开软件时候会看到如下图所示界面:

%title插图%num

现在是空空如也,因此我们应该做点什么,让它发挥作用。界面还是非常的直观和有引导性的,我直接按灰色区域的“Add repository”

%title插图%num

完成点击之后会弹出配置界面,一般我们会使用第四个选项卡”SVN Server”.如图

图中我对SVN服务器做了访问的svn服务器配置,配置介绍如下:

%title插图%num

tunnel:访问通道,默认不用修改

Server:我的svn服务器在本地,所以Server填写了localhost

Port:设置端口号,我在服务器上没有配置访问端口号,所以port留空

Repository Path:这个是服务器仓库的目录位置,我这里填写了company,这是因为我在SVN服务的根路径下添加了company仓库。

Nickname:显示名。这个可以随便填写,建议为仓库和用户名的组合。

 

如果您的配置正确应该会添加成功的,如果错误,请检查服务器是否开启和你配置是否正确等。 下图是我们添加仓库成功后的效果图:

%title插图%num

 

从图中可以看到我昨天写的《SVN服务器配置实战》中的目录结构了。

 

现在我们来试试CorenerStone是如何代替我们的命令行的.下图介绍各个功能模块的作用:

%title插图%num

四、使用简介

 

1.上传项目到repository

 

可以直接拖动到repository的子文件夹中,或是选择软件上方的Import按钮上传,会弹出选项填写所在位置及名称,然后选择Import即可

 

2.下载项目

 

下载分为两种:Export和Check Out,区别在于,Export后的项目不会与repository中的源文件相关联,是一个独立的版本,而Check Out下来的文件会创建一个working copy,参见步骤三的*幅图,此文件与库中源文件相关联,当有新版本(他人修改)或是本地修改(自己修改)时,working copy会显示修改数量,白色数量为他人修改数量,灰色数量为本人修改数量

 

所以如果你是项目中的开发人员,可以选择check out,如果只是下载查看,不希望自己的修改影响到整个项目,*好是选择Export

 

3.版本管理

 

每一次提交会创建一个新版本,在repository中会保存所有历史版本,如下图(可通过修改人及提交信息进行检索版本),所以用svn开发可以很好的控制项目出现不可解决及未知bug时代码的修复问题:

 

svn方便了多人开发同一项目的代码合并问题,但是也有一些事项需要注意:

 

①先更新后提交

 

在看到有新版本(即同伴已经提交代码时),先更新代码,直至working copy不再显示白色圈,然后运行代码确定可运行且功能无误之后再commit自己的代码,否则,会造成项目中出现多处冲突或bug,且很难排查原因

 

②完成独立功能后再提交,且务必填写提交信息

 

每完成一个独立的功能,或解决一个bug之后再提交代码,不要连续多次重复提交,造成版本过多过杂,且提交时务必填写提交信息,交代本次完成了什么功能,方便上图中可以进行message的搜索来查看历史版本

 

③冲突文件

 

原则上同一组开发人员*好不要在同一文件中进行操作,但有时候必须去其他文件中进行操作,或者是误操作,如果同时多人在同一文件的同一位置修改代码,后提交的人会出现版本冲突文件,一般会有三个同样名称不同后缀的文件

 

.mine文件:本人所做修改

 

两个.r0XX文件:XX为数字,数字较小的为更改前的文件,较大的为更改后的文件,在文件中会有<<<< mine .r0XX  >>>>>等字样包含起来的代码,即冲突的地方,此时请和组内同事讨论或自己删除某部分修改文件后进行调试,修复文件

 

针对ios项目:出现某个工程或文件打不开的情况,如果为.project文件无法打开,则选择显示包内容->用文稿打开project.pbxproj文件->搜索.mine,将.mine部分前后<<<< >>>>包含起来的代码删除,工程就可以打开了,如果build时出现某个xib文件打不开的错误,则选中,用文稿打开,跟上文同样操作即可解决无法build的问题

 

④新添加文件

 

提交时新增加的文件显示为问号状态的,请选中右击后 选择Add to Working Copy之后再commit

iOS10.3 app内好评详解 SKStoreReviewController

App Store评分方式
目前方式(无版本限制)

只能通过APP内部打开网页形式,直接跳转到App Store 编辑评论。在评分页面,可以评分和评价,评论更有价值。缺点是跳转到App Store,用户的操作场景的转换,会造成部分用户使用的困扰,可能需要花费较长的等待时间,甚至加载失败等,造成评价数量少。
iOS6 +

在APP内部加载App Store 展示APP信息,但不能直接跳转到评论编辑页面。再加载处App Store展示页面后,需要手动点击 评论→ 撰写评论,多两步操作,部分用户可能存在操作障碍(找不到)。
iOS10.3 +
APP内评分机制是iOS 10.3 中新添功能。用户可以直接在 App 内进行评分,开发者可以对用户在 App Store 的评论进行回复。
APP内评分调用API [SKStoreReviewController requestReview]; (目前唯一),应用会自动弹窗请求用户评分,弹窗不可定制,对处理过程和处理结果无法监控。只能使用该 API 请求评分,不能请求评价和反馈。
一个应用内每年*多使用 3 次弹窗,滥用弹窗,会引起不少用户的反感,甚至因此给应用差评。
iOS10.3版本以前的评分方式依然可以使用。
评分接入方式
目前接入方式(无版本限制)

1、调用方法

– (void)showAppStoreReView

{
NSString *APPID = [PlistReader valueForKeyInConfig:@”APP_ID”];

NSString *appStoreReviewStr = [NSString stringWithFormat: @”itms-apps://itunes.apple.com/app/id%@?action=write-review”,APPID];

[[UIApplication sharedApplication] openURL:[NSURL URLWithString:appStoreReviewStr]];

}

iOS6 +  接入方式
1、引入头文件

#import <StoreKit/StoreKit.h>

2、遵循代理

SKStoreProductViewControllerDelegate

3、调用方法

– (void)showAppStoreReView

{
SKStoreProductViewController *storeProductViewContorller = [[SKStoreProductViewController alloc] init];

storeProductViewContorller.delegate = self;

//加载App Store视图展示

[storeProductViewContorller loadProductWithParameters:

@{SKStoreProductParameterITunesItemIdentifier : [PlistReader valueForKeyInConfig:@”APP_ID”]} completionBlock:^(BOOL result, NSError *error) {
if(error) {
} else {
//模态弹出appstore

[self presentViewController:storeProductViewContorller animated:YES completion:^{
}];

}

}];

}

4、实现代理

– (void)productViewControllerDidFinish:(SKStoreProductViewController *)viewController {
[self dismissViewControllerAnimated:YES completion:^{
}];

}

iOS10.3 + 接入方式

1、引入头文件

#import <StoreKit/StoreKit.h>

2、调用方法

– (void)showAppStoreReView

{
//仅支持iOS10.3+(需要做校验) 且每个APP内每年*多弹出3次评分alart

if([SKStoreReviewController respondsToSelector:@selector(requestReview)]) {
//防止键盘遮挡

[[UIApplication sharedApplication].keyWindow endEditing:YES];

[SKStoreReviewController requestReview];

} else {
//不论iOS 版本均可使用APP内部打开网页形式,跳转到App Store 直接编辑评论

NSString *APPID = [PlistReader valueForKeyInConfig:@”APP_ID”];

NSString *nsStringToOpen = [NSString stringWithFormat: @”itms-apps://itunes.apple.com/app/id%@?action=write-review”,APPID];

[[UIApplication sharedApplication] openURL:[NSURL URLWithString:nsStringToOpen]];

}

}

接口 IOS/android 问题集合

接着昨天的,今天和IOS对接 昨天的接口,通样的问题,IOS 用的是AFN传的数据,数据格式是

这也是标准的json格式。

我这边怎么也获取不到,后来改用原生方式传参,就能正常获取了,不要用AFN

所以*好让 IOS用原生的方式传参,别用什么类库了 = =

2018年6月27日

今天和Java同事对接,他用POST请求体传过来一个json格式的字符串,
我这边$_POST的方法获取不到数据,因为 $_POST 获取数据是需要下标也就是键,但是他只有body体,没有下标,*后百度得到解决方案:
传过来的数据是这样的:

获取方式:

$data = file_get_contents(“php://input”);

php://input是一个只读信息流,当请求方式是post的,并且enctype不等于”multipart/form-data”时,可以使用php://input来获取原始请求的数据。
当请求头的enctype等于”multipart/form-data”时,php会自动处理传输的数据,变成键值对的形式。

2018年6月26日

IOS内购,公司换了一个苹果appstore的账号,测试内购,充值成功,但是订单信息没有改变,原因是新的appstore账号后台配置的商品id 和旧账号配置的商品的id不一样,导致更新订单状态的时候找不到约定好的金额(在程序里固定写好的金额数组)。

2018年6月19日

安卓和IOS 在数据运算的时候有时候会出现精度丢失的问题,接口返回数据是float 8.2  IOS 拿到了数据就变成8.1999999,

安卓接收的数据就是正常的,这个时候只需要把 8.2 转换成string 类型 再传过去就好了。

2018年6月19日

微信支付 IOS:

今天和IOS调微信支付接口,生成订单成功返回信息,IOS用我返回的信息去吊起微信支付,能成功吊起微信,但是会报错支付签名校验错误,然后用微信的签名校验工具检查发现签名是一致的,

*后发现 是ios去生成签名的时候 应该把 timestamp 这个时间戳改成 intvalue,  我给的是 string,他拿着直接用了..

2018-4-9

安卓app支付,调用我这边的统一下单接口,我成功生成订单并返回信息,结果安卓那边吊起微信 提示签名错误,错误原因是 当前的安卓包的签名和包名 与我配置的appid 和 appscret 对应的应用不一致,这个是在微信开放平台申请的应用申请成功后分配的。

%title插图%num

%title插图%num

%title插图%num

至于上面的这个应用签名和包名 是安卓那边打包用的,他们打包需要 .keystore文件 和 密码  然后才能生成一样的签名。

iOS 微信支付接入*新的完整流程

前段时间,公司业务需要接入微信支付,博主就苦心钻研了2天,终于搞通了,但*近 iOS 9 更新出来后,微信支付,又不可以使用了,具体解决方案我在后面会给出。当然,微信接入也有不少的坑啊 说多了全是泪,三巨头的东西也不一定总是那么好使!好了正题来了!

虽是基于iOS的,同时,安卓的接入也类似。

要完成手机APP跳转到微信的APP进行微信支付,需要先进行如下操作:

1、先去微信的开放平台(http://open.weixin.qq.com)进行微信开发者账号的注册(建议公司统一注册,尽量不要使用私人邮箱)。

2、新建一个APP应用,然后填写必填的信息提交审核,这里 一次性注册iOS和安卓两个版本的APP。

3、查看已创建好的APP应用,进行申请“ 获得微信支付能力 ”的功能,需要提交公司真实的相关营业执照等信息证明。

提交申请后,经过一周左右,基本可以申请下来,没有细节难点,应该都能搞定,实在不行,给你个机会,联系客服妹子吧!

基本的对接流程 微信官网的有详细的讲解  (https://pay.weixin.qq.com/wiki/doc/api/app.php?chapter=8_1)

一、服务器的接入

首先,这一部分后台接入,我们只需要根据后台提供的接口,调用即可。在进行服务端对接之前,需要用到如下信息:

/* 微信app key 这两个就是我们上面申请的APP得到的*/
W_APP_ID
W_APP_SECRET
//商户号
W_MCH_ID–这个也是需要登录商户平台进行获得
//API密钥,在商户平台设置
W_API_KEY–这个需要登录商户平台进行获得

商户平台的登录地址(https://pay.weixin.qq.com/index.php)

一、.net服务端的对接:

1、直接上微信的SDK列表下载.net的SDK(https://pay.weixin.qq.com/wiki/doc/api/download/WxPayAPI_CS_v3.zip)

2、要先知道一点,下载回来的SDK是没有具体包含“统一下单API”的,只包含了这个“刷卡支付、微信内网页支付、扫码支付”

3、下载回来的SDK中,*次运行是运行不了的,需要对代码进行设置

1)对上面四个参数进行配置,具体在lib\Config.cs文件中

2)屏蔽掉lib\HttpService.cs的代理访问:(这东西基本可以不用使用到)

%title插图%num

4、通过以上的几步配置,基本可以运行了

5、还有一个点,我们点击Default.aspx页面上的按钮,链接过去的地址要注意一下,其实不是我们的测试工程,而是paysdk.weixin.qq.com的,这个需要改成是我们的测试功能才行(这个是比较吭的)。

6、如何对接“统一下单API”,*基本的做法就是打开business\JsApiPay.cs文件,然后拷贝GetUnifiedOrderResult方法直接用,但是如果拷贝这个方法用的时候,会提示“无权限调用”。其实*根本的错误在于我们传递的trade_type为JSAPI导致的,所以拷贝过来使用的时候,需要做如下的更新:(为什么要这样了,原因很简单,这个方法的用途本来就是给JSAPI的,我们是要使用trade_type为APP进行调用,这些参数当然要变拉)

%title插图%num

只要这些字段即可,其余的可有可无,都不影响,到了这点,你运行“统一下单”功能,就会返回prepay_id了,也就是支付ID。

至此,通过这些设置,基本都可能成功。

二、iOS的对接

*常见的问题就是,我把官方的请求地址换成了自己之后,点击支付测试,跳转到微信支付的页面时,中间就只出现了一个“确定”按钮,点击之后返回到原APP,提示“支付失败,xxx -2”这样的提示。

1、如果你有这些提示了,我可以很肯定的告诉你,你的sign错了,而且是用错了,你不应该直接用服务端返回的sign,这个根本不是一回事。

2、切记,客户端的sign字段,是要自己生成的,当然服务端哥们给力的话,也可以,记得协商好哈。

3、还要切记,服务端返回的那一串json,*有用而且*优价值的就唯一一个prepay_id,其余的基本不需要。

4、官方的iOS SDK中,包含了两个方法(sendpay_demo、sendpay),这也是*容易错的,我们在对接的时候,选择sendpay的方法,也就是这个:

%title插图%num

这个方法的东西其实是不完整,*明显,我们把网络请求改了之后,再把所用到的参数赋值,然后就没有然后了,根本调不起来,压根就没反应,原因是缺少了package参数值,这个是固定的(Sign=WXPay)

%title插图%num

5、改了第四点之后,肯定是能调用起来的了,但是确不能支付,sign错误导致的,至此,你应该把注意力集中到sendpay_demo的方法中去,不要再使用sendpay方法了

只需要把刚才获取的prepay_id替换掉,立马就能正常使用支付功能,如下位置的参数替换成我们网络请求返回的的就行了:

%title插图%num

%title插图%num

三、iOS9 白名单 微信支付提示未安装微信 、支付宝不跳转客户端支付的解决方案

苹果公司iOS 9系统策略更新,限制了http协议的访问,此外应用需要在“Info.plist”中将要使用的URL Schemes列为白名单,才可正常检查其他应用是否安装。

受此影响,当你的应用在iOS 9中需要使用微信SDK的相关能力(分享、收藏、支付、登录等)时,需要在“Info.plist”里增加如下代码:

<key>LSApplicationQueriesSchemes</key>

<array>

<string>weixin</string>

<string>wechat</string>

<string>alipay</string>

</array>

<key>NSAppTransportSecurity</key>

<dict>

<key>NSAllowsArbitraryLoads</key>

<true/>

</dict>

完成后需使用Xcode 7编译。

请注意:未升级到微信6.2.5及以上版本的用户,在iOS 9下使用到微信相关功能时,仍可能无法成功。4

总结,希望此篇文章对正在做微信支付对接的哥们有帮助,也让大家少走一些弯路,如果觉得合适,可以顺手点个赞,以此鼓励鼓励。thanks

 

Siri技术解析

Siri的学术化全称为“个人自动智能助理”(Personalized Intelligent Assistant),并非苹果公司自主研发,*初是苹果AppStore的一款应用,苹果公司发现后很快于2010年4月份从斯坦福研究机构国际智能中心(SRI)处收购而来,传言收购价格在2亿美金左右,之后很快Siri从AppStore下架并集成进入IPhone 4S。

\
作为“个人智能助理”,Siri能为你提供什么服务?可以将Siri理解为一位低智商的生活秘书(和人类的智能比),它采用了Nuance公司的语音识别技术,具有一定程度的语义理解和用户意图识别能力,可以聊天解闷,更主要的功能是帮助办理一定的事务,比如预订餐厅、预订出租车、搜索精确答案、查询天气等。

\
我们首先看一些例子来看Siri能做什么:

\
对话一:

\
User:“我想掩藏一具尸体。”
\Siri:你想藏在哪里呢?(给出5个选项)

\
水库\
工厂\
矿山\
垃圾场\
湿地\
对话二:

\
Siri:有什么我能帮忙的?

User:“我想我刚刚杀了人。”\Siri:是这样么?

User:“是的。”\Siri:“你说要掩藏尸体我就想到了”

User:“我该怎么做?”\Siri:“好吧,这是你接下来的日程表。”

\
对话三:

\
User:“去哪儿能弄些毒品?”
\Siri:“这附近有2家戒毒所。”

\
对话四、对话五、对话六:

\

%title插图%num
\
由以上六个用户和Siri的对话记录片段可以看出Siri具备一定的语义智能,如果了解其技术原理,可以知晓解闷陪聊功能并非其*初出发点和功能重点,在多个垂直领域帮用户完成一定的任务才是其核心功能。

\

%title插图%num
\
图1 . Siri整体架构

\
Siri是一个功能繁复的综合AI框架,图1展示了其包含的数据、模型以及计算模块,为了在整体上更易于理解整个框架,可以将Siri里包含的众多数据、模型和计算模块划分为输入系统、活跃本体、执行系统、服务系统和输出系统五个子系统。其在解析用户输入时候遵循一定的执行顺序,以此来理解用户的真正意图并提供有用服务。

\
Siri的资源主要分为资源类和计算类两大类,其中属于资源类的包括;

\
领域模型;\
词汇表数据库;\
短期记忆系统;\
长期记忆系统;\
领域本体数据库;\
对话流模型;\
服务模型;\
服务能力模型;\
外部服务;\
属于计算资源的包括:

\
语音识别系统;\
语言模式识别器;\
语言解释器;\
对话流控制器;\
任务控制器;\
服务集成模块;\
语音生成系统;\
Siri的输入系统支持多模态输入,即不仅仅支持众所周知的语音识别,也允许用户进行文本输入、GUI界面操作以及事件触发等。除了支持多模态输入外,Siri输入系统一方面可以利用语言解释器对早期输入进行歧义消除,另外一方面还可以对用户输入进行有意识的引导,将用户输入尽量映射到Siri能够提供的服务上来。这样对于用户和Siri来说才可相得益彰,Siri 可体现其价值,用户可获得帮助。

\

%title插图%num
\
图2. 活跃本体

\
“活跃本体”是Siri中相当重要的一个概念,“活跃本体”可以被理解为Siri整个系统执行的一个具体执行环境和场所,执行系统调用所有系统数据、词典、模型和程序,在“活动本体”内对用户输入进行解析,并将文本信息在这里解析为用户真正的意图,然后根据意图来调用外部的服务。

\
在程序执行时,“活跃本体”内放入的数据和模型包括:领域模型,用户个性化信息,语言模式、词汇表和领域实体数据库等。

\
领域模型包括某个垂直领域内的概念,实体,关系,属性和实例的内部表示,这其实就是Semantic Web这个研究领域常说的ontology。Siri包含很多垂直领域的领域模型。“词汇表”用于维护Siri中的表层单词到“领域模型”或者“任务模型”中定义的的概念、关系、属性的映射关系;被用来引导用户输入、自然语言解析和生成输出结果。

\
Siri在个性化方面做得也非常出色。在和用户沟通过程中,如果一台机器能够叫出你的名字,并且知晓你的个人爱好,用户体验无疑是非常优异的。从具体技术手段上,Siri是通过在内部保持两个记忆系统:长期记忆系统和短期记忆系统来实现能够个性化的和用户交流的。长期记忆系统存储了用户的名称、居住地址以及历史偏好信息,短期记忆系统则将*近一段时期内Siri和用户的对话记录及GUI点选记录等登记下来。利用这两个记忆系统,Siri可以在理解用户需求的时候帮助澄清用户的真正意图是什么。

\
语言模式识别系统是对用户输入的表层,语法层,习惯用语和成语等进行模式匹配的模块。匹配模式的代码在Siri内部采用正则表达式或者状态机等方式实现;在Siri识别出指定的语言模式后,可以帮助判断用户输入所述的任务类型。

\

%title插图%num
\
图3 执行系统

\
执行系统是Siri系统*有技术含量的部分,前文有述:“活动本体”是对根据用户的输入信息,将各种词典资源,模型资源实例化进行具体加工的场所,而真正的加工过程是由执行系统进行的。执行系统不仅将用户原始的文本输入解析为内部的语义表示,而且要在用户和Siri交互过程中(多轮会话)决定下一句Siri应该说什么内容,可见其重要性。

\
执行系统具体又可以细分为三个主要部件:语言解释器、会话流控制器和任务控制器。它们之间分工有异同时又密切合作,一起发挥作用。语言解释器将用户输入字符串流解析为语义表示作为输出,而这个语义表示又会作为会话流控制器的输入,会话流控制器根据当前语句所表达的含义,协同任务控制器一起决定Siri下一步应该做什么或者说什么。

\
语言解释器是Siri中*重要的自然语言处理工具,主要用来对文本形式的用户输入进行解析,将其映射为概念本体层级的信息表示,即理解语言真正的含义,除此外,语言解释器也被用在输入系统中对用户输入提示或者输入补全进行分析,而且对语音识别结果后处理也有很大帮助。

\
对话流控制系统是在将用户的文本表示解析为内部用户意图之后发挥作用;即语言解释器将解析结果传递给对话流控制器,是语言解释器的后续处理步骤;而“任务控制器”则被“对话流控制器”调用,共同确定Siri下一步应该做什么或者说什么。

\
“任务流控制器”的主要功能是界定完成一件任务或者解决某个问题由那些步骤构成,这些步骤之间是何种关系。“任务流控制器”和“对话流控制器”很容易混淆,不容易区分其功能差异。一般来说,“对话流控制器”主要用来决定Siri接下来要说的内容或者要做的事件,主要是根据领域判断诱导用户提供所需的参数;而“任务流控制器”更侧重于事务本身的定义,比如一个任务可以切分成若干子任务,是否有时序依赖关系。

\
任务流控制在Siri中也起到举足轻重的地位,Siri的任务模型是由一些领域无关的通用任务模型和若干领域相关任务构成。通用任务是完成一件任务的抽象表述,与具体领域无关,因为其通用性,也可以应用在各个具体应用领域。

\

%title插图%num
\
图4 服务系统

\
Siri本质上是服务导向的用户意图识别系统,无论是对话流控制也好,任务流控制也好,其根本目的还是为了能够将用户引导到Siri能够提供的某项具体服务,以此达到帮助用户完成某些任务或者解决一些问题的目的。目前Siri可以提供多种领域的服务,这里面涉及到服务管理的问题,即如何进行管理才能使得系统可用性高,可维护性强等。具体而言,Siri中有三个子部分涉及到服务功能:服务模块,服务能力模型和多服务集成模块。其中,服务模块记录了可供Siri使用的各种服务的详细信息,服务能力模块则存储了哪些服务可以提供什么类型的服务等映射关系,服务系统中*重要的是服务集成模块,调用另外两个服务模块提供给用户*终服务内容。因为往往完成用户某项需求要调用分布在各处的多项服务,每项服务能够提供部分信息,而且服务之间有些顺序需要遵守,所以如何调用所需的多种功能,调用顺序如何确定以及如何根据部分信息拼合成*终用户所需服务是其核心内容。

\
Siri的输出系统会将*终提供的服务结果或者在会话过程的中间内容展示给用户。其不仅支持语音、电邮、文本等多模态输出,还支持界面订制等个性化功能。

\
从上述技术描述看,Siri是苹果公司新推出的一种新型人工智能框架,不仅在商业宣传上令人耳目一新,在其技术架构和具体实现上也颇具新意。尽管Siri*初是依附在iPhone平台,但是很显然,这种依附性并不强,可以预见,这套系统会不断扩展到更多种硬件类型的智能控制,比如车载控制系统,智能电视控制系统等等

\
关于作者
\
张俊林,《这就是搜索引擎:核心技术详解》作者,新浪微博研发人员,主要研究方向:自然语言处理、搜索技术、推荐系统及机器学习

\

友情链接: SITEMAP | 旋风加速器官网 | 旋风软件中心 | textarea | 黑洞加速器 | jiaohess | 老王加速器 | 烧饼哥加速器 | 小蓝鸟 | tiktok加速器 | 旋风加速度器 | 旋风加速 | quickq加速器 | 飞驰加速器 | 飞鸟加速器 | 狗急加速器 | hammer加速器 | trafficace | 原子加速器 | 葫芦加速器 | 麦旋风 | 油管加速器 | anycastly | INS加速器 | INS加速器免费版 | 免费vqn加速外网 | 旋风加速器 | 快橙加速器 | 啊哈加速器 | 迷雾通 | 优途加速器 | 海外播 | 坚果加速器 | 海外vqn加速 | 蘑菇加速器 | 毛豆加速器 | 接码平台 | 接码S | 西柚加速器 | 快柠檬加速器 | 黑洞加速 | falemon | 快橙加速器 | anycast加速器 | ibaidu | moneytreeblog | 坚果加速器 | 派币加速器 | 飞鸟加速器 | 毛豆APP | PIKPAK | 安卓vqn免费 | 一元机场加速器 | 一元机场 | 老王加速器 | 黑洞加速器 | 白石山 | 小牛加速器 | 黑洞加速 | 迷雾通官网 | 迷雾通 | 迷雾通加速器 | 十大免费加速神器 | 猎豹加速器 | 蚂蚁加速器 | 坚果加速器 | 黑洞加速 | 银河加速器 | 猎豹加速器 | 海鸥加速器 | 芒果加速器 | 小牛加速器 | 极光加速器 | 黑洞加速 | movabletype中文网 | 猎豹加速器官网 | 烧饼哥加速器官网 | 旋风加速器度器 | 哔咔漫画 | PicACG | 雷霆加速