<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[追风之影]]></title>
  <link href="http://ashen-zhao.github.io/atom.xml" rel="self"/>
  <link href="http://ashen-zhao.github.io/"/>
  <updated>2024-01-10T17:47:22+08:00</updated>
  <id>http://ashen-zhao.github.io/</id>
  <author>
    <name><![CDATA[Ashen]]></name>
    <email><![CDATA[zhaoashen@gmail.com]]></email>
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[在Storyboard中为view添加圆角等扩展属性]]></title>
    <link href="http://ashen-zhao.github.io/blog/2020/06/24/kuozhan/"/>
    <updated>2020-06-24T17:51:57+08:00</updated>
    <id>http://ashen-zhao.github.io/blog/2020/06/24/kuozhan</id>
    <content type="html"><![CDATA[<h4>为了方便在Storyboard面板中给View设置圆角属性, 实现和原生其他属性一样设置的方式. 现通过<code>IBInspectable</code> 在storyboard中给view添加扩展属性;</h4>

<h4>效果图</h4>

<p><img src="http://ashen-zhao.github.io/images/kuozhanxiaoguotu.png" alt="在Storyboard中为view添加圆角等扩展属性" /></p>

<!--more-->


<h4>代码实现</h4>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>extension UIView {
</span><span class='line'>    @IBInspectable var cornerRadius: CGFloat {
</span><span class='line'>        get {
</span><span class='line'>            return layer.cornerRadius
</span><span class='line'>        }
</span><span class='line'>        set {
</span><span class='line'>            layer.cornerRadius = newValue
</span><span class='line'>        }
</span><span class='line'>    }
</span><span class='line'>    @IBInspectable var maskToBounds: Bool {
</span><span class='line'>        get {
</span><span class='line'>            return layer.masksToBounds
</span><span class='line'>        }
</span><span class='line'>        set {
</span><span class='line'>            layer.masksToBounds = newValue
</span><span class='line'>        }
</span><span class='line'>    }
</span><span class='line'>    @IBInspectable var borderColor: UIColor {
</span><span class='line'>        get {
</span><span class='line'>            return UIColor.init(cgColor:  layer.borderColor!)
</span><span class='line'>        }
</span><span class='line'>        set {
</span><span class='line'>            layer.borderColor = newValue.cgColor
</span><span class='line'>        }
</span><span class='line'>    }
</span><span class='line'>    @IBInspectable var borderWidth: CGFloat {
</span><span class='line'>        get {
</span><span class='line'>            return layer.borderWidth
</span><span class='line'>        }
</span><span class='line'>        set {
</span><span class='line'>            layer.borderWidth = newValue
</span><span class='line'>        }
</span><span class='line'>    }
</span><span class='line'>   
</span><span class='line'>}</span></code></pre></td></tr></table></div></figure>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[iOS进阶之逆向工程（越狱、砸壳、反编译）]]></title>
    <link href="http://ashen-zhao.github.io/blog/2019/08/14/ni-xiang-bian-cheng/"/>
    <updated>2019-08-14T17:51:57+08:00</updated>
    <id>http://ashen-zhao.github.io/blog/2019/08/14/ni-xiang-bian-cheng</id>
    <content type="html"><![CDATA[<h3>背景</h3>

<p>这篇文章只是我的一个记录，记录我是如何一步一步的，从越狱一部手机到反编译一个APP，故不作为教程文章，只为自己以后方便复现，文章内容大部分从别人文章中采集整合，如若使用，仅供参考。</p>

<h3>第一步、越狱</h3>

<p>关于越狱看<a href="https://baijiahao.baidu.com/s?id=1626241403987098895&amp;wfr=spider&amp;for=pc">这篇文章</a>足以，这里简单对这篇文章做下记录：<br/>
1、用苹果手机自带的Safari浏览器打开app.ignition.fun<br/>
2、进去后点击中间的按钮<br/>
3、点击Jailbreaks<br/>
4、点击Jailbreaks进去后拉倒最后点击Pwn20wnd<br/>
5、点击GET然后点安装<br/>
6、去设置信任证书，如果无法信息，卸载重新下载<br/>
7、打开刚才安装的unc0ver APP<br/>
8、点击「Jailbreak」按钮，越狱过程可能会重启三次，每次重启后再打开unc0ver APP点击Jailbreak按钮。<br/>
9、出现Cydia后代表越狱成功<br/>
注：如果越狱过程中，卡住OTA问题上，请到设置->存储管理里删除已经下载好的系统文件，如果删除了还是不行的话，请自行谷歌或者百度, 我因为有部专门测试手机，我选择了直接重置手机。懒得去找其他办法了。</p>

<h3>第二步、砸壳</h3>

<h4>这里选择一键砸壳工具frida-ios-dump</h4>

<p>frida-ios-dump<a href="https://github.com/AloneMonkey/frida-ios-dump">下载地址</a></p>

<!--more-->


<h4>1、先安装frida</h4>

<h5>首页安装pip，打开终端，执行以下命令(如果已安装请跳过)</h5>

<p><code>sudo easy_install pip</code></p>

<h5>其次，执行以下命令安装frida</h5>

<p><code>sudo pip install frida-tools</code><br/>
如果安装报以下错误,<br/>
<code>Uninstalling a distutils installed project (six) has been deprecated and will be removed in a future version. This is due to the fact that uninstalling a distutils project will only partially uninstall the project.</code><br/>
执行以下命令，<br/>
<code>sudo pip install frida –upgrade –ignore-installed six</code><br/>
然后重新执行,<br/>
<code>sudo pip install frida-tools</code></p>

<h4>2、使用你的越狱手机，启动 Cydia，安装frida插件</h4>

<p>软件源 Sources-> 编辑 Edit（右上角）-> 添加 Add（左上角）-> 输入 <code>https://build.frida.re</code>，通过刚才添加的软件源安装 frida 插件。</p>

<h4>3、通过USB链接手机和电脑</h4>

<p>具体如何链接ssh这里<a href="https://blog.csdn.net/youshaoduo/article/details/81097802">有篇文章</a>, 我这里做简单记录：<br/>
1、在手机上打开<code>Cydia</code>，搜索<code>openssh</code>并安装<br/>
2、在Mac终端执行<code>brew install libimobiledevice</code><br/>
3、完成第二步后执行<code>iproxy 2222 22</code>,进行端口转换，此时终端界面显示<code>waiting for connection</code><br/>
4、打开新的终端执行<code>ssh -p 2222 root@127.0.0.1</code>, 这时候可能会出现   <code>The authenticity of host '[127.0.0.1]:2222 ([127.0.0.1]:2222)' can't be established.
ECDSA key fingerprint is SHA256:+0hOqiykO/N5kh9p+mYk2pb+2MAb5Q1DkFK9tTCZ7TU.
Are you sure you want to continue connecting (yes/no)?</code>.
输入yes后按回车，此时会提示你输入手机的root密码，默认密码是：alpine  ，然后之前的那个<code>waiting for connection</code>终端窗口，就显示连接成功了。</p>

<h4>4、执行<code>frida-ps -U</code> 查看手机上安装的app</h4>

<p>新开一个终端,执行<code>frida-ps -U</code> 即可在终端显示已安装app</p>

<h4>5、cd到已经下载的<code>frida-ios-dump</code>目录，执行以下命令安装依赖库  <code>sudo pip install -r requirements.txt --upgrade</code></h4>

<h4>6、开始砸壳</h4>

<p>终端执行以下命令<br/>
<code>./dump.py app名称</code><br/>
这里的app名称为在手机桌面上显示的名称，砸壳完成后，会在frida-ios-dump目录里生成一个已砸壳的ipa文件，即可脱壳的app。</p>

<h4>7、判断是否砸壳</h4>

<p>判断是否砸壳，进入app目录- otool -l WeChat  | grep crypt</p>

<h3>安装 MonkeyDev、Reavl、 Hopper</h3>

<h5>安装 <a href="https://github.com/AloneMonkey/MonkeyDev/wiki/%E5%AE%89%E8%A3%85">MonkeyDev</a></h5>

<h5>安装 <a href="https://www.jianshu.com/p/51c539f61ab0">Reveal</a></h5>

<h5>安装 <a href="https://download.csdn.net/download/arr0813/10600870">Hopper Disassemble</a></h5>

<p>先把工具安装了，后续可能会继续更新，如何使用。</p>

<h3>参考文章</h3>

<p><a href="https://baijiahao.baidu.com/s?id=1626241403987098895&amp;wfr=spider&amp;for=pc">https://baijiahao.baidu.com/s?id=1626241403987098895&amp;wfr=spider&amp;for=pc</a><br/>
<a href="https://blog.csdn.net/youshaoduo/article/details/81133492">https://blog.csdn.net/youshaoduo/article/details/81133492</a><br/>
<a href="https://blog.csdn.net/youshaoduo/article/details/81097802">https://blog.csdn.net/youshaoduo/article/details/81097802</a><br/>
<a href="http://mobile.51cto.com/hot-573146.htm">http://mobile.51cto.com/hot-573146.htm</a><br/>
<a href="https://www.jianshu.com/p/28eb7616fd3a">https://www.jianshu.com/p/28eb7616fd3a</a><br/>
<a href="https://blog.csdn.net/skylin19840101/article/details/54669815">https://blog.csdn.net/skylin19840101/article/details/54669815</a><br/>
<a href="http://kuailejim.com/2016/04/25/%E6%89%8B%E6%8A%8A%E6%89%8B%E6%95%99%E4%BD%A0%E5%8F%8D%E7%BC%96%E8%AF%91%E5%88%AB%E4%BA%BA%E7%9A%84app/">http://kuailejim.com/2016/04/25/%E6%89%8B%E6%8A%8A%E6%89%8B%E6%95%99%E4%BD%A0%E5%8F%8D%E7%BC%96%E8%AF%91%E5%88%AB%E4%BA%BA%E7%9A%84app/</a><br/>
<a href="http://www.alonemonkey.com/2018/01/30/frida-ios-dump/">http://www.alonemonkey.com/2018/01/30/frida-ios-dump/</a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[一行代码搞定UITextField的输入格式限制]]></title>
    <link href="http://ashen-zhao.github.io/blog/2018/08/16/textfield/"/>
    <updated>2018-08-16T14:00:16+08:00</updated>
    <id>http://ashen-zhao.github.io/blog/2018/08/16/textfield</id>
    <content type="html"><![CDATA[<h3>ZASTextFieldFormat开发背景</h3>

<p>   在开发的过程中，每次写到UITextField，就不由得心里不爽，因为要考虑到各种输入限制，实现代理、通知等一些麻烦繁琐的东西，就心中不爽，所以才写了这个<a href="https://github.com/ashen-zhao/uitextfieldformat">ZASTextFieldFormat</a>简单的轮子，先暂时用着，等后期在慢慢优化完善。</p>

<h3>ZASTextFieldFormat 简介</h3>

<p>一行代码，设置UITextField的输入格式限制，比如手机号、身份证号、银行卡号格式以及输入字符类型个数的限制等；</p>

<h3>接口说明</h3>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>
</span><span class='line'>/**
</span><span class='line'> * ZASTextFieldFormatDelegate代理
</span><span class='line'> *
</span><span class='line'> */
</span><span class='line'>@property (nonatomic, assign) id&lt;ZASTextFieldFormatDelegate&gt; zasDelegate;
</span><span class='line'>
</span><span class='line'>/**
</span><span class='line'> * 设置浮点类型,只允许输入两位小数的浮点类型（default=NO）
</span><span class='line'> * 
</span><span class='line'> */
</span><span class='line'>@property (nonatomic, assign) Boolean isFloat;
</span><span class='line'>
</span><span class='line'>/**
</span><span class='line'> * 设置正则匹配模式（如果设置正则模式，则忽略其他格式限制）
</span><span class='line'> *
</span><span class='line'> */
</span><span class='line'>@property (nonatomic, copy) NSString * pattern;
</span><span class='line'>
</span><span class='line'>/**
</span><span class='line'> * 设置UITextFiled格式控制的入口 (注：这个入口必须被调用)
</span><span class='line'> * format=nil或者""则不限制格式, charactersInString=nil或者""则不限制字符, maxLimit=0则不限制个数
</span><span class='line'> *
</span><span class='line'> * 示例: 以手机号为例
</span><span class='line'> * @param format              格式，eg: ### #### ####
</span><span class='line'> * @param charactersInString  支持输入的字符，eg: 0123456789
</span><span class='line'> * @param maxLimit            最大输入限制个数，eg: 11
</span><span class='line'> * 结果输入：159 1234 5678
</span><span class='line'> */
</span><span class='line'> - (void)textFieldWithFormat:(NSString *)format charactersInString:(NSString *)charactersInString maxLimit:(NSInteger)maxLimit;</span></code></pre></td></tr></table></div></figure>


<h3>具体使用</h3>

<p>使原有UITextField继承自ZASTextFieldFormat，然后调用如何接口即可；</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>[_tfPhone textFieldWithFormat:@"### #### ####" charactersInString:@"0123456789" maxLimit:11];</span></code></pre></td></tr></table></div></figure>


<h3>参考Demo</h3>

<p><a href="https://github.com/ashen-zhao/uitextfieldformat">点击此处获取Demo</a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[自动生成混淆文件(swift版)]]></title>
    <link href="http://ashen-zhao.github.io/blog/2018/07/10/zi-dong-sheng-cheng-swifthun-yao-wen-jian/"/>
    <updated>2018-07-10T14:00:16+08:00</updated>
    <id>http://ashen-zhao.github.io/blog/2018/07/10/zi-dong-sheng-cheng-swifthun-yao-wen-jian</id>
    <content type="html"><![CDATA[<h3>起因</h3>

<p>你们都知道，AppStore审核机制，多款类似的APP，会被4.3拒绝，至于如何规避4.3，这里我只写如何给项目添加混淆代码（又叫垃圾代码），当然只添加垃圾代码，应该是规避不了4.3的，但至少可以迷惑机审，加大通过机审的概率，至于其他方法，不予多说。 我这里使用python脚本，自动生成swift垃圾文件代码，文件名随机，每个文件中含有少量变量，方法等。</p>

<h3>实现原理</h3>

<p>实现原理很简单，就是创建文件，向文件中，添加swift语言的字符串即可。</p>

<h3>实现代码</h3>

<p><a href="https://github.com/ashen-zhao/createSwift">获取代码Demo文件点击此处</a> 以下为实现代码</p>

<!--more-->


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
<span class='line-number'>69</span>
<span class='line-number'>70</span>
<span class='line-number'>71</span>
<span class='line-number'>72</span>
<span class='line-number'>73</span>
<span class='line-number'>74</span>
<span class='line-number'>75</span>
<span class='line-number'>76</span>
<span class='line-number'>77</span>
<span class='line-number'>78</span>
<span class='line-number'>79</span>
<span class='line-number'>80</span>
<span class='line-number'>81</span>
<span class='line-number'>82</span>
<span class='line-number'>83</span>
<span class='line-number'>84</span>
<span class='line-number'>85</span>
<span class='line-number'>86</span>
<span class='line-number'>87</span>
<span class='line-number'>88</span>
<span class='line-number'>89</span>
<span class='line-number'>90</span>
<span class='line-number'>91</span>
<span class='line-number'>92</span>
<span class='line-number'>93</span>
<span class='line-number'>94</span>
<span class='line-number'>95</span>
<span class='line-number'>96</span>
<span class='line-number'>97</span>
<span class='line-number'>98</span>
<span class='line-number'>99</span>
<span class='line-number'>100</span>
<span class='line-number'>101</span>
<span class='line-number'>102</span>
<span class='line-number'>103</span>
<span class='line-number'>104</span>
<span class='line-number'>105</span>
<span class='line-number'>106</span>
<span class='line-number'>107</span>
<span class='line-number'>108</span>
</pre></td><td class='code'><pre><code class=''><span class='line'># -*- coding: utf-8 -*-
</span><span class='line'>
</span><span class='line'>import random
</span><span class='line'>
</span><span class='line'>import os,sys
</span><span class='line'>
</span><span class='line'>import string
</span><span class='line'>
</span><span class='line'>#创建.swift文件
</span><span class='line'>
</span><span class='line'>def createSwift(fileNmae,propertyNumber,methodArray):
</span><span class='line'>
</span><span class='line'>    full_path =  sys.path[0] + '/SwiftFiles/' + fileNmae + '.swift'
</span><span class='line'>
</span><span class='line'>    file = open(full_path, 'w')
</span><span class='line'>
</span><span class='line'>    file.write('//\n//  '+fileNmae+'.swift\n//  Orange\n\n//  Created by Ashen on 18/06/06.\n//  Copyright ©  2018年 BeiLian. All rights reserved.\n//\n\n')
</span><span class='line'>
</span><span class='line'>    file.write('import UIKit \n\n' + 'class '+fileNmae+': UIViewController {\n\n')
</span><span class='line'>    
</span><span class='line'>    propryNameArray = []
</span><span class='line'>
</span><span class='line'>    for index in range(1,propertyNumber):
</span><span class='line'>
</span><span class='line'>        propryNameArray.append(random.choice(array))
</span><span class='line'>
</span><span class='line'>    propryNameArray = list(set(propryNameArray))
</span><span class='line'>
</span><span class='line'>    for propertyName in propryNameArray:
</span><span class='line'>
</span><span class='line'>        file.write('    public var '+propertyName+':'+random.choice(classArray)+'!\n')
</span><span class='line'>
</span><span class='line'>    file.write('\n\n')
</span><span class='line'>    
</span><span class='line'>    file.write('    override func viewDidLoad() {\n        super.viewDidLoad()\n    }\n\n')
</span><span class='line'>   
</span><span class='line'>
</span><span class='line'>    for methodName in methodArray:
</span><span class='line'>
</span><span class='line'>        file.write('    public func '+methodName+'TOVC() {\n\n       var realArr = Array&lt;String&gt;()\n')
</span><span class='line'>
</span><span class='line'>        number = random.randint(3, 10)
</span><span class='line'>
</span><span class='line'>        for i in range(1,number):
</span><span class='line'>
</span><span class='line'>            file.write('       realArr.append("'+random.choice(array)+'")\n')
</span><span class='line'>
</span><span class='line'>        file.write('\n    }\n\n')
</span><span class='line'>
</span><span class='line'>    file.write('}')
</span><span class='line'>
</span><span class='line'>    file.close()
</span><span class='line'>
</span><span class='line'>    print('Done')
</span><span class='line'>
</span><span class='line'>
</span><span class='line'>def createClassName():
</span><span class='line'>    
</span><span class='line'>    first = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
</span><span class='line'>
</span><span class='line'>    second = "abcdefghijklmnopqrstuvwxyz"
</span><span class='line'>
</span><span class='line'>    index = 0
</span><span class='line'>
</span><span class='line'>    array = []
</span><span class='line'>
</span><span class='line'>    # 设置生成多少个类
</span><span class='line'>    classNumber = 3
</span><span class='line'>    for i in range(classNumber):
</span><span class='line'>
</span><span class='line'>        final=(random.choice(first))
</span><span class='line'>
</span><span class='line'>        index = random.randint(3, 5)
</span><span class='line'>
</span><span class='line'>        for i in range(index):
</span><span class='line'>
</span><span class='line'>            final+=(random.choice(second))
</span><span class='line'>
</span><span class='line'>        final += (random.choice(first))
</span><span class='line'>
</span><span class='line'>        for i in range(index):
</span><span class='line'>
</span><span class='line'>            final+=(random.choice(second))
</span><span class='line'>
</span><span class='line'>        array.append(final)
</span><span class='line'>    return array
</span><span class='line'>
</span><span class='line'>#属性类型
</span><span class='line'>classArray = ['UIColor','UILabel','UITableView','UISlider','UIScrollView','UIView','UIButton']
</span><span class='line'>
</span><span class='line'>array = createClassName()
</span><span class='line'>
</span><span class='line'>array = list(set(array))
</span><span class='line'>
</span><span class='line'>for name in array:
</span><span class='line'>
</span><span class='line'>    number = random.randint(3, 10)
</span><span class='line'>
</span><span class='line'>    methodArray = []
</span><span class='line'>
</span><span class='line'>    for i in range(1,5):
</span><span class='line'>
</span><span class='line'>        methodArray.append(random.choice(array))
</span><span class='line'>
</span><span class='line'>    methodArray = list(set(methodArray))#数组去重
</span><span class='line'>    
</span><span class='line'>    createSwift(name+'VController',number,methodArray)
</span><span class='line'> </span></code></pre></td></tr></table></div></figure>



]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[工具篇之自定义检查版本更新提示弹框]]></title>
    <link href="http://ashen-zhao.github.io/blog/2018/03/14/geng-xin/"/>
    <updated>2018-03-14T18:06:58+08:00</updated>
    <id>http://ashen-zhao.github.io/blog/2018/03/14/geng-xin</id>
    <content type="html"><![CDATA[<h3>引言</h3>

<p>对于一些app的更新弹框，使用系统自带的Alert弹框，文字排版总是对不齐，没有美观，像我这样有点强迫症的，看到都别扭，更别说去点击更新了，于是乎，就自己动手做了一个，不管怎么样，看着舒服多了。</p>

<h3>此处不废话，看效果</h3>

<p><img src="http://ashen-zhao.github.io/images/checkUpdate.png" alt="" /></p>

<h3>使用</h3>

<p>由于这个工具开发过于简单，我这里就不讲述如何开发实现的了，想要看具体实现的，我已在github上公开源码（<a href="https://github.com/ashen-zhao/ZASUpdateAlert">ZASUpdateAlert</a>），可自行查看去吐槽。</p>

<!--more-->


<p>本着学习的态度，写了这个工具，又本着学习的态度，上传到了cocoapods上面，也是人生第一次上传代码到cocoapods，着实搞了一个下午，传了删，删了又传，最终也算是成功了。</p>

<p>鉴于我搞了半天才搞定如何上传自己的库到cocoapods，后续我会写一篇基础教材，到底该如何上传，同时也为自己以后再次使用时，少走坑，快速实现人生理想。</p>

<h4>CocoaPods安装</h4>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>pod 'ZASUpdateAlert', '~&gt; 0.1.0'</span></code></pre></td></tr></table></div></figure>


<h4>手动安装</h4>

<p>只需将<code>ZASUpdateAlert</code>文件夹拖到项目中。</p>

<h4>使用示例</h4>

<p>如果是使用的是CocoaPods，第一步需要先导入ZASUpdateAlert</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>import ZASUpdateAlert</span></code></pre></td></tr></table></div></figure>




<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>ZASUpdateAlert.show(version: "V1.6", content: "1.全新UI界面\n2.更好的性能体验\n3.投诉系统极速反馈\n4.多个BUG虫的尸体都不复存在", appId: "xxxxxxxx", isMustUpdate: false)</span></code></pre></td></tr></table></div></figure>


<h4>示例源代码</h4>

<p><a href="https://github.com/ashen-zhao/ZASUpdateAlert">点击查看ZASUpdateAlert源码去吐槽喽</a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[《三体》之读后随记]]></title>
    <link href="http://ashen-zhao.github.io/blog/2017/12/12/santi/"/>
    <updated>2017-12-12T14:07:08+08:00</updated>
    <id>http://ashen-zhao.github.io/blog/2017/12/12/santi</id>
    <content type="html"><![CDATA[<h3>《三体》启蒙</h3>

<p>&nbsp;&nbsp;对于宇宙，我始终有一种感触，却无法形容这种感触，它是那么的神秘莫测，那么的不可思议以至于我就算开发大脑的全部，也无法解读它。我喜欢宇宙，喜欢天体，喜欢那寂静无限深渊的星空，或许我是一个宇宙科幻迷，宇宙科幻迷当然要看看《三体》，看它是如何的来打开那灵魂深处的思想禁锢。</p>

<h3>《三体》微感</h3>

<p>&nbsp;&nbsp; 大约3977页，耗时58小时3分，我读完了《三体》的全部三部，页数是微信读书上面的页面，读纸质书，有时候会犯困也不那么方便，我喜欢电子书的方便快捷。读完三体后，让我脑洞大开，宇宙中真是无奇不有呀，什么三体人，什么水滴等等，都让我眼界大开，思想得到了扩展，心灵得到了升华。</p>

<p>第一部，涉及的宇宙比较少，可能没有多少引起我的注意，或许读的也间隔比较久，印象比较深的就是汪淼的那个时间，以及叶文洁与红岸基地，还有三体发射到地球的两个智子（三体人用质子，展开多维建造成的超级超级超级计算机）；</p>

<p>第二部，地球人制定的面壁计划无疑是可笑而又无力的表现，罗辑也只是被绑架的救世主，却也在人们的地位起起伏伏，在这一部中，最震撼的，最有视觉冲击力的，应该就是那水滴攻击舰队的壮观场面了，我想拍成电影的话，如果能还原大刘的90%，应该就足以体现那旷世的震撼，这部中，让人深思的应该就是黑暗森林法则，让人感觉自己是多么的渺小，地球是多么的渺小，太阳系又是多么渺小，对于高级文明，摧毁太阳系也只需要发射一枚光粒武器而已。</p>

<!--more-->


<p>第三部，以重叠前两部时间，不同的视角来慢慢开展。从魔法师之死一节中，给多维空间埋下伏笔。这部我的总体感觉就是，进程太快了，从三体世界被摧毁后，然后是太阳系被二向箔二维化，一切都是那么的快，特别是太阳系被二维化的过程中，总感觉地球会最终保留下来，可大刘却没那么大气，最终整个太阳系一切虚无。剩下程心和AA乘光速飞船飞去云天明送给她的恒星系，在她们飞去的过程中，让我最烧脑的就时间与速度的参照系，光速飞船里的人，光速飞行后几百光年后的恒星系，在飞船里却只过了几十个小时，而外界却过去了几百年，让我始终无法深理解。在她们到达目的恒星系后，大刘好像把一切进程又加快了，什么光速飞船、黑线、黑域、小宇宙，都让人大开眼界，不得不说，看到这里，突然有种宇宙也没多大的感觉，乘坐光速飞船，在有生之年是可以从宇宙的这头穿越到宇宙的那头。宇宙重生、宇宙膨胀、宇宙质量流失等等，都让人感觉宇宙的神秘却也不神秘了，宇宙之无限，却也有限了。小宇宙的存在，感觉就是BUG，宇宙重生却也影响不了小宇宙，时间之外的小宇宙，难道就是宇宙之中最高级的发明了吗？不禁让人深思，大刘还不会写三体第四部呢？</p>

<h3>《三体》纪年事件对照表</h3>

<p>&nbsp;&nbsp;三体虽然已经看完，但却对里面的时间与事件的关联顺序，有些乱糟糟的，索性我就找了一个三体纪年事件对照表，来帮自己理理思绪。以下内容是我在网上找的，并非我本人整理，时间对照表也只是对照一个大概而已，如果要想精细，我想只能请大刘亲自出马了。</p>

<h4>魔法时代(公元 1453 年 5 月 03 日 16 时 &mdash;&ndash; 公元 1453 年 5 月 28 日 21 时)</h4>

<p>1453 年 5 月 03 日 16 时 高维碎片接触地球。<br/>
1453 年 5 月 28 日 21 时 碎片完全离开地球, 魔法时代结束。</p>

<h4>疯狂年代(公元 1966 年 &mdash;&ndash; 公元 1979 年)</h4>

<p>1967 年 叶文洁目睹父亲叶哲泰惨死。<br/>
1968 年 红岸基地建立。<br/>
1969 年 叶文洁遭白沐霖陷害， 入狱后被雷志成和扬卫宁带回红岸基地。 这一事件 成为其后人类历史的一个转折点。 <br/>
1971 年秋 叶文洁发现太阳电波放大功能， 人类文明第一次以恒星级功率向宇宙发出讯息。<br/>
1973 年 叶文洁与杨卫宁结婚。 <br/>
1979 年 10 月 21 日凌晨 叶文洁收到三体文明的回复讯息， 并再次回答。 下午， 叶文洁杀死雷志成和扬卫宁， 成功掩盖自己对人类文明的超级背叛。</p>

<h4>黄金时代(公元 1980 年 &mdash;&ndash; 公元 2007 年)</h4>

<p>1980 年 6 月 杨冬出生。<br/>
1982 年 叶文洁离开红岸基地， 回到清华大学任教。 不久后在西北山区第一次遇到伊文斯。 <br/>
1985 年 叶文洁第二次见到伊文斯， 向其告知外星文明的存在。<br/>
1987 年 红岸基地关闭。<br/>
1988 年冬 叶文洁来到第二红岸基地， 地球三体运动诞生。 <br/>
1989 年 陈 XX14 岁生日， 第一次目睹球状闪电， 将其作为终生探索目标。《球状闪电》 <br/>
1991 年 白沐霖在加拿大渥太华去世。<br/>
2002 年 陈 XX 在泰山邂逅林云。《球状闪电》 <br/>
2005 年 陈 XX 提出球状闪电激发设想， 并获得证实。 不久， 丁仪成功揭示球状闪电的秘密，宏粒子被发现。《球状闪电》 <br/>
2005 年 “科学边界” 学会成立。 <br/>
2006 年 在中国罗布泊进行了第一次宏原子聚变实验， 林云死亡。《球状闪电》 <br/>
2006 年 智子到达地球， 人类科学被锁死。 <br/>
2006 年 由 SETI 项目主管诺顿. 帕克主持的球状闪电研究发现超级观察者。《球状闪电》 <br/>
2007 年 旺淼在良湘的工地上见到杨冬。</p>

<h4>危机纪元【危机纪元元年(公元 2008 年) &mdash;&ndash; 危机纪元 208 年(公元 2216 年) 】</h4>

<p>危机纪元元年 6 月 6 日晚上 杨冬自杀身亡。 <br/>
危机纪元元年 6 月 8 日下午 汪淼受邀首次参加作战中心会议。 <br/>
危机纪元元年 6 月 9 日 汪淼开始受到智子蛊惑。 <br/>
危机纪元元年 6 月 14 日 00: 00-05: 00 智子二维展开， 制造宇宙背景辐射波动假象， 汪淼被彻底迷惑。 <br/>
危机纪元元年 叶文洁在杨冬墓前向罗辑讲述宇宙文明公理。<br/>
危机纪元元年 三体世界由于害怕人类思维不透明， 中断了与三体组织“降临派” 的联系。<br/>
危机纪元元年 叶文洁参加三体叛军集会时被捕。 <br/>
危机纪元元年 史强策划“古筝行动”， 成功夺取被三体组织 “降临派” 截留的三体文明讯息，伊文思在行动中被杀。 <br/>
危机纪元 3 年 程心进入行星防御理事会战略情报局， 在局长托马斯维德的领导下设计并参与“阶梯计划”。 <br/>
危机纪元 3 年 章北海进入太空军。 同年， “逃亡主义” 被联大宣布为非法。 <br/>
危机纪元 3 年 “面壁计划” 实行， 罗辑被指定为“面壁者”， 之后利用特权找到庄颜。 <br/>
危机纪元 3 年 哈勃二号太空望远镜观察到三体舰队航迹， 三体入侵被最终证实。 <br/>
危机纪元 4 年 “群星计划” 启动， 云天明在安乐死前为程心购买恒星 DX3906。 <br/>
危机纪元 7 年 “阶梯计划” 实行， 程心第一次进入冬眠。 <br/>
危机纪元 8 年 面壁者泰勒的“量子舰队计划” 被识穿， 随后自杀。 面壁者希恩斯和雷迪亚兹进入冬眠。 <br/>
危机纪元 8 年 根据罗辑的计划， 人类向全宇宙发出针对恒星 187J3X1 的坐标广播， 之后罗辑进入冬眠。 <br/>
危机纪元 12 年 丁仪领导的核聚变研究取得成功。 章北海谋杀主张“工质驱动飞船” 的三个专家， 促使“辐射驱动飞船” 成为主要研究方向。 <br/>
危机纪元 12 年 哈勃二号太空望远镜观察到三体舰队向太阳系发射了十个探测器。 <br/>
危机纪元 16 年 面壁者希恩斯发明“思想钢印” 并投入使用。 恒星型氢弹在水星进行试验。稍后， 面壁者雷迪亚兹的“水星坠落计划” 被识破， 最后被本国人民用石头砸死。 <br/>
危机纪元 154 年 恒星 187J3X1 被“光粒” 摧毁。 <br/>
危机纪元 198 年 丁仪苏醒， 于北京大学物理系任教。 <br/>
危机纪元 204 年 人类观测到恒星 187J3X1 被摧毁。 <br/>
危机纪元 205 年 章北海、 罗辑从冬眠中苏醒。 章北海被任命为“自然选择号” 执行舰长。 <br/>
危机纪元 205 年“面壁计划” 被中止， 罗辑与希恩斯丧失面壁者身份。 稍后， 希恩斯被其妻子山彬惠子以破壁人身份揭穿其失败主义者及逃亡主义者的真面目。 <br/>
危机纪元 205 年“水滴” 到达太阳系， 章北海挟持“自然选择号” 逃亡。 末日战役爆发， 人类太空武装力量全军覆没， 丁仪阵亡。 <br/>
危机纪元 205 年“黑暗战役” 爆发， 章北海阵亡。 <br/>
危机纪元 205 年“水滴” 进入太阳同步轨道， 对太阳进行全频段电波压制， 人类丧失宇宙广播能力。 <br/>
危机纪元 205 年“面壁计划” 恢复， 罗辑被指定为唯一的“面壁者”。<br/>
危机纪元 208 年秋 罗辑单枪匹马， 成功建立对三体世界的 “黑暗森林”威慑， 危机纪元结束。</p>

<h4>威摄纪元【威摄纪元 1 年(公元 2217 年) &mdash;&ndash; 威摄纪元 62 年(公元 2278 年) 】</h4>

<p>威慑纪元 5 年 罗辑、 庄颜母女与两个半世纪前向地球发出警告的 1379 号监听员交谈。 <br/>
威慑纪元 12 年“青铜时代号” 被引诱返回地球， 所有人遭逮捕。 <br/>
威慑纪元 13 年“青铜时代号” 目标甄别员史耐德向“蓝色空间” 号发出警告，“蓝色空间号”加速逃离， “万有引力号” 起航追击。 <br/>
威慑纪元61 年 艾AA发现DX3906拥有两颗行星， 程心因为 DX3906星系的所有权问题被唤醒，托马斯维德为成为执剑人谋杀程心， 未遂。 <br/>
威慑纪元 61 年“蓝色空间号” 与“万有引力号” 进入“智子盲区”， 与太阳系的实时通讯中断。 <br/>
威慑纪元 62 年 程心当选执剑人。 <br/>
威慑纪元 62 年 11 月 28 日 16 时 17 分 罗辑向程心交接引力波宇宙广播系统。 奥尔特星云外， 水滴闪击“蓝色空间号” 与“万有引力号”。   威慑纪元 62 年 11 月 28 日 16 时 27 分 程心放弃威慑操作， 地球引力波宇宙广播系统遭到摧毁。 与此同时，“水滴” 恢复对太阳的电波压制， 人类进行宇宙广播的途径被彻底封死， 威慑纪元终止。</p>

<h4>威摄后(公元 2278 年 11 月 28 日 16 时 27 分 58 秒后 &mdash;&ndash; 公元 2279 年)</h4>

<p>威慑后第 1 天 “万有引力” 号启动引力波宇宙广播， 三体星系坐标暴露。 <br/>
威慑后第 38 天 “林格-菲兹罗” 望远镜观察到三体第二舰队航迹， 并发现其已达光速。 <br/>
威慑后 41 天后 智子发表“保留地声明”， 全人类开始向澳大利亚移民。<br/>
威慑后第 1 年， 移民结束后第 6 天 地球得知“万有引力” 号启动了引力波宇宙广播， 三体力量全部撤出太阳系， 广播纪元开始。</p>

<h4>广播纪元【广播纪元 1 年(公元 2280 年) &mdash;&ndash; 广播纪元 59 年(公元 2338 年) 】</h4>

<p>广播纪元 3 年 10 月 三体星系被摧毁。 <br/>
广播纪元 7 年 三体世界毁灭的光信号到达地球， “黑暗森林” 理论得到最后证实。 <br/>
广播纪元 7 年 “茶座谈话”， 人类从智子口中获知可以通过某种方法避免“黑暗森林” 打击。 <br/>
广播纪元 7 年 云天明与程心在拉格郎日点通过智子建立的量子通讯信道进行实时会面。人类从云天明传递的情报中获知“曲率驱动” 及如何发布“安全声明” 的讯息。 <br/>
广播纪元 8 年 “林格-菲兹罗” 望远镜发现曲率驱动航迹， 不久， 禁止曲率驱动研究的法律出台， 曲率驱动研究成为非法。 <br/>
广播纪元 8 年 程心将星环集团交与托马斯维德， 继续曲率驱动研究， 之后与艾 AA 进入冬眠。</p>

<h4>掩体纪元【掩体纪元元年(公元 2339 年) &mdash;&ndash; 掩体纪元 67 年(公元 2406 年) 】</h4>

<p>掩体纪元 11 年 5 月 “星环城事件”， 程心被苏醒。 托马斯维德遵守对程心的诺言， 向政府投降， 托马斯维德被处以极刑， 曲率驱动研究被逼中止。 程心再次冬眠。 <br/>
掩体纪元 46 年 曲率驱动研究在水星基地恢复。 <br/>
掩体纪元 63 年 三套曲率驱动引擎制造完成， 开始进行试航。 <br/>
掩体纪元 65 年 太阳系坐标暴露， 外星文明发动“黑暗森林” 打击。 <br/>
掩体纪元 66 年 “启示号” 与“阿拉斯加号” 起航探测外星发射物。 1 号曲率驱动引擎被安装到“星环号” 上。 <br/>
掩体纪元 67 年 5 月 白 ICE 回忆起 192 年前与丁仪在沙漠中的谈话， 从中受到启发， 悟出维度打击真相， 向太阳系政府示警。 <br/>
掩体纪元 67 年 5 月 19 日 程心与艾 AA 被唤醒， 乘“星环号” 前往冥王星， 再次见到罗辑。 <br/>
掩体纪元 67 年 5 月 19 日 “星环号”起航后两小时， 太阳系人类历史上最后一份重要文件 《 “黑暗森林” 打击公告》 发表。 <br/>
掩体纪元 67 年 太阳系文明在维度打击中彻底毁灭， 程心与艾 AA 乘“星环号” 逃离太阳系，以光速前往 DX3906 星系。</p>

<h4>银河纪元(公元 2283 年 &mdash;&ndash; ？ )</h4>

<p>银河纪元 409 年 程心与艾 AA 到达 DX3906 星系， 在蓝星表面遇到关一凡。 <br/>
银河纪元 409 年 云天明来到 DX3906 星系；“死线” 扩散， DX3906 星系变成“黑域”， 程心与关一帆被困“亨特” 号飞船穿梭机。</p>

<h4>DX3906 星系黑域纪元(总计 18906416 年)</h4>

<p>程心与关一帆进入 647 号宇宙。</p>

<h4>647 号宇宙时间线</h4>

<p>小宇宙时间线第 2 年， 大宇宙上百亿年后， 收到来自大宇宙的超模广播。 广播信息同时使用157 万个文明的文字进行表述， 在这宇宙文明审判日的“生死薄” 上， 地球文明赫然在列</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Xcode修改版权Copyright、统一配置类前缀]]></title>
    <link href="http://ashen-zhao.github.io/blog/2017/12/01/copyright/"/>
    <updated>2017-12-01T13:51:07+08:00</updated>
    <id>http://ashen-zhao.github.io/blog/2017/12/01/copyright</id>
    <content type="html"><![CDATA[<h4>修改类的Copyright、类前缀</h4>

<p>对于已经在项目中的文件，想要修改版权信息，使用全局替换就可以了，而对于新文件来说，想让Xcode帮你自动填充版权方，也是很方便的，之前都是傻瓜式的替换，现在发现了新大陆，就来这里记录下吧，具体操作流程如下图：<br/>
<img src="http://ashen-zhao.github.io/images/copyright.png" alt="版权、前缀" /></p>

<p>顺便加点料，对于有些项目，需要为每个类加一个前缀，也是可以按照这个流程来做的，设置上图中的<code>Class prefix</code>就可以了，这样Xcode会在新建的类的时候自动填充这个前缀了。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[React-Native初体验]]></title>
    <link href="http://ashen-zhao.github.io/blog/2017/08/23/react-native/"/>
    <updated>2017-08-23T17:25:41+08:00</updated>
    <id>http://ashen-zhao.github.io/blog/2017/08/23/react-native</id>
    <content type="html"><![CDATA[<h3>我的学习之React-Native</h3>

<p>练习项目：<a href="https://github.com/ashen-zhao/react-native">https://github.com/ashen-zhao/react-native</a></p>

<h4>目前还在学习阶段，日后有时间有精力了，再来补充这篇文章吧（偷笑中），又来欺骗自己了，啥时候来补充呀，这个还真不知道呀，谁让咱都是性情中人呢。</h4>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Xcode代码全黑的另一种解决办法]]></title>
    <link href="http://ashen-zhao.github.io/blog/2017/07/14/xcodedai-ma-quan-hei/"/>
    <updated>2017-07-14T16:44:48+08:00</updated>
    <id>http://ashen-zhao.github.io/blog/2017/07/14/xcodedai-ma-quan-hei</id>
    <content type="html"><![CDATA[<h4>Xcode代码全黑且没有智能提示，应该算是开发中最烦恼的事之一了吧，一旦遇到这样问题，之前除了Clean项目，删除DerivedData文件夹，然而这样并没有什么用，偶尔重启Xcode或许运气好的话，彩色世界就会回来了。</h4>

<h4>运气为什么好就能回来了，联想到Xcode比较吃内存，在联想到我苦逼的4g内存，估计Xcode代码全黑，可内存有联系呀，瞬间茅塞顿开呀，赶紧打开活动监视器，看到占用内存最多的 SourceKitService，大概百度了下SourceKitService这个进程，也没发现有什么比较严重的东东，就退出SourceKitService这个进程，回到Xcode发现，代码不再是全黑了，又回到彩色世界了，世界又是那么的美好，编程也变得快乐了</h4>

<h4>总结，Xcode代码全黑的另一种解决办法，就是打开活动监视器，退出SourceKitService进程，就可以了。</h4>

<p>注：可能只针对内存比较小的电脑（另外：我的项目是swift项目）</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[UITableView重用机制导致CABasicAnimation动画失效]]></title>
    <link href="http://ashen-zhao.github.io/blog/2017/03/02/dong-hua-shi-xiao/"/>
    <updated>2017-03-02T18:24:49+08:00</updated>
    <id>http://ashen-zhao.github.io/blog/2017/03/02/dong-hua-shi-xiao</id>
    <content type="html"><![CDATA[<p>开发随记，再给cell上添加一个小动画图片时，遇到一个很蛋疼的问题，动画明明会动，而且退出后台在回来也会动，可就是拉出屏幕外，在回来时，动画失效了，不会动了。以下是动画代码，就是一个简单的摇摆动画</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>let rotationAnim = CABasicAnimation(keyPath: "transform.rotation.z")
</span><span class='line'>            rotationAnim.toValue = M_PI/5
</span><span class='line'>            rotationAnim.autoreverses = true
</span><span class='line'>            rotationAnim.repeatCount = MAXFLOAT
</span><span class='line'>            rotationAnim.duration = 0.2
</span><span class='line'>            rotationAnim.isRemovedOnCompletion = false
</span><span class='line'>            moveImgv.layer.add(rotationAnim, forKey: nil)</span></code></pre></td></tr></table></div></figure>


<!--more-->


<p>于是就开始看CABasicAnimation的类的属性说明，该设置的都设置了，可还是不行，百度，谷歌，搜狗统统找不到原因，全是CABasicAnimation的简单教程。</p>

<p>无奈至极呀，就开始检查代码，看有没有可以修改的地方，一通乱世只会，在上面代码中的最后一行<br/>
<code>moveImgv.layer.add(rotationAnim, forKey: nil)</code></p>

<p>我发现forkey是nil，可当我给它一个值的时候，</p>

<p><code>moveImgv.layer.add(rotationAnim, forKey: "moveanimation")</code><br/>
再次调试，却发现重用后，动画终于可以动了，原来我废了那么久的时间，却是这样的问题，真是想哭，又想笑😁。</p>

<p>就是这样的问题，在网上找了好久，却找不到结果，可能是大家都写了key了吧，在此写下这边文章，希望有遇到像我一样的问题的同学可以找到解决办法。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[《自我营销七堂课》读书心得]]></title>
    <link href="http://ashen-zhao.github.io/blog/2017/02/24/zi-wo-ying-xiao-qi-tang-ke-du-hou-gan/"/>
    <updated>2017-02-24T14:55:48+08:00</updated>
    <id>http://ashen-zhao.github.io/blog/2017/02/24/zi-wo-ying-xiao-qi-tang-ke-du-hou-gan</id>
    <content type="html"><![CDATA[<p>为什么选择这本书来读呢？或许是自己错过太多表现自我的机会，亦或是有人说我不懂得自我营销，亦或者羡慕他人侃侃而谈&hellip;. 于是就本着学习自我营销的方法，来读这本书的，前前后后也差不多花了一个月的时间，中间是断断续续的，不管怎么着这也是个读书的开始，哪怕不是一个完美的开局，或许会有一个完美的结局。</p>

<!--more-->


<p>读一本简单，可写读书心得却不容易，不知写些什么，也不知从何写起，或许是没有把书读透。<br/>
我不打算对本书的每一章就行分析解读，我只是把我读书时的想法写出来，算是个读书笔记吧，亦或者一个引子，提醒自己以后看到这些个点点滴滴的记录，就会提醒自己读过这本书，再去回忆书中的内容，然后在考虑读这本书的意义以及成长。</p>

<p>“我承认认真是做好一件事的根本，可要想只有认真就想让别人认同你，远远不够，你需要去争取，更要圆滑点，不争即为输”<br/>
“抓住对方需要的情感，不就是揣摩对方心思么，需要了解对方需要什么，才能用对应的情感，感化他人吧”</p>

<p>“找不到对的，错的也不要选，就要结婚一样，遇不到对的人，错的选了也会出很多问题，工作也是一样，切莫拿错的来将就，那只会越来越糟糕”</p>

<p>“物虽相同，人不同，阶层改变了物的表象。同一款产品，不同的颜色，富人与穷人，价格却天壤之别，穷人买来用，富人买来让别人看，各有所需，各有所求，全看买的用处，价格之差也就没那么明显了”</p>

<p>“朦朦胧胧的读了近一半了，可却没有什么记忆深刻的，可能是本书本身就不是以故事为主题的，而是以一些案例为主题，案例很多，可都是已经成功的案例，不知道到成功背后经历过什么，或许拿成功案例来讲，就是本书的一种自我营销吧”</p>

<p>“有多少人可以没有一点不爽的接受别人的错误指责呢？或许是有的，那他一定也会很色吧”</p>

<p>“打造自己独特的特性，才能让人记住你，前提是你需要表现你的特性。不要告诉我，你喜欢沉默，可沉默不会告诉别人你有多厉害，除非你已经是很牛逼的人物了，那样沉默才是你的代名词”</p>

<p>“凡是有的，还要给他，使他更有，但凡没有的，连他所有的，也要夺去。工作亦是如此，你越表现突出，机会就会越多，越会让你表现，反倒你越是不爱表现，机会就会越少，到最后仅有的机会也会给你剥夺”</p>

<p>“第一次，就做第一名。给你的才能一次机会，让别人有机会就会想起你能做好”</p>

<p>“马太效应。好则越好，坏则越坏”</p>

<p>“原文：我们生于一个同质化产品过剩的时代，如果你不高调的展示出自己独特的个性符号，那么，你就很难有机会绽放光彩，过于低调的人生前途往往暗淡。”</p>

<p>“高调自我，谈何容易”</p>

<p>“生于忧患死于安乐，恰恰说明’狠角色‘，存在的价值，你要有危机感，才能促使自己不断的进步，而这个危机感，就是那个'狠角色', 他可能抢你风头，可能当众打击你，可能替代你&hellip;.,加油吧，尽可能的让自己成为狠角色”</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[iOS自动打包上传脚本]]></title>
    <link href="http://ashen-zhao.github.io/blog/2017/02/22/autobuild/"/>
    <updated>2017-02-22T16:46:25+08:00</updated>
    <id>http://ashen-zhao.github.io/blog/2017/02/22/autobuild</id>
    <content type="html"><![CDATA[<p>自从将swift2.2升级到swift3.0, 每次使用Xcode8编译都很慢，很是不爽，于是有了研究下xcodebuild命令行打包的想法，起初不知道用shell，还是用python, 在网上大概搜了一下，关于python的比较多点，于是就先学习python的基础语法，然后再去看看大神的一些脚本，就开始专研命令行打包了。总之，过程很艰辛，结果很满意，以下便是我修改后的<a href="https://github.com/ashen-zhao/autobuild">python自动打包脚本</a>，命令行使用，打包完成会询问是否上传蒲公英平台，以及询问是否上传appstore，还有是否保留archive文件。<br/>
<a href="https://github.com/ashen-zhao/autobuild">自动打包脚本下载地址</a></p>

<!--more-->


<h3>使用方法</h3>

<p>1、下载完成后，将autobuild.py以及exportOptions.plist文件放到你的项目跟目录下（即与xx.xcworkspace或者xx.xcworkspace在同一个目录下）<br/>
2、打开autobuild.py，修改配置信息<br/>
3、打开命令终端，进入项目根目录<br/>
&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;a.如果你是xx.xcodeproj<br/>
&emsp;&emsp;    <code>./autobuild.py -p youproject.xcodeproj</code><br/>
&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;b.如果你是xx.xcworkspace<br/>
&emsp;&emsp; <code>./autobuild.py -w youproject.xcworkspace</code></p>

<p>4、等待终端回应，依据终端提示进行相关操作<br/>
5、最终会在桌面生成带有时间戳的文件夹，含义ipa以及xcarchive文件</p>

<pre>
#!/usr/bin/env python
# -*- coding:utf-8 -*-

#./autobuild.py -p youproject.xcodeproj
#./autobuild.py -w youproject.xcworkspace

import argparse
import subprocess
import requests
import os
import datetime

#configuration for iOS build setting
CONFIGURATION = "Release"
EXPORT_OPTIONS_PLIST = "exportOptions.plist"

#发布版本号
VERSION = '1.0.0'
BUILD = '17021803'

#要打包的TARGET名字
TARGET = 'ULife'

#Info.plist路径
PLIST_PATH = "xxxxxx/Info.plist"

#存放路径以时间命令
DATE = datetime.datetime.now().strftime('%Y-%m-%d_%H.%M.%S')

#会在桌面创建输出ipa文件的目录
EXPORT_MAIN_DIRECTORY = "~/Desktop/" + TARGET + DATE

#xcarchive文件路径（含有dsym），后续查找BUG用途
ARCHIVEPATH = EXPORT_MAIN_DIRECTORY + "/%s%s.xcarchive" %(TARGET,VERSION)

#ipa路径
IPAPATH = EXPORT_MAIN_DIRECTORY + "/%s.ipa" %(TARGET)

#苹果开发者账号
APPLEID = 'xxxxxx'
APPLEPWD = 'xxxxx'

# configuration for pgyer
PGYER_UPLOAD_URL = "http://www.pgyer.com/apiv1/app/upload"
DOWNLOAD_BASE_URL = "http://www.pgyer.com"
USER_KEY = "xxxxxx"
API_KEY = "xxxxx"
#设置从蒲公英下载应用时的密码
PYGER_PASSWORD = "xxxxx"

def cleanArchiveFile():
    cleanCmd = "rm -r %s" %(ARCHIVEPATH)
    process = subprocess.Popen(cleanCmd, shell = True)
    process.wait()
    print "cleaned archiveFile: %s" %(ARCHIVEPATH)

def uploadIpaToAppStore():
    print "iPA上传中...."
    altoolPath = "/Applications/Xcode.app/Contents/Applications/Application\ Loader.app/Contents/Frameworks/ITunesSoftwareService.framework/Versions/A/Support/altool"

    exportCmd = "%s --validate-app -f %s -u %s -p %s -t ios --output-format xml" % (altoolPath, IPAPATH, APPLEID,APPLEPWD)
    process = subprocess.Popen(exportCmd, shell=True)
    (stdoutdata, stderrdata) = process.communicate()

    validateResult = process.returncode
    if validateResult == 0:
        print '~~~~~~~~~~~~~~~~iPA验证通过~~~~~~~~~~~~~~~~'
        exportCmd = "%s --upload-app -f %s -u %s -p %s -t ios --output-format normal" % (
        altoolPath, IPAPATH, APPLEID, APPLEPWD)
        process = subprocess.Popen(exportCmd, shell=True)
        (stdoutdata, stderrdata) = process.communicate()

        uploadresult = process.returncode
        if uploadresult == 0:
            print '~~~~~~~~~~~~~~~~iPA上传成功'
        else:
            print '~~~~~~~~~~~~~~~~iPA上传失败'
    else:
        print "~~~~~~~~~~~~~~~~iPA验证失败~~~~~~~~~~~~~~~~"

def parserUploadResult(jsonResult):
    resultCode = jsonResult['code']
    if resultCode == 0:
        downUrl = DOWNLOAD_BASE_URL +"/"+jsonResult['data']['appShortcutUrl']
        print "Upload Success"
        print "DownUrl is:" + downUrl
    else:
        print "Upload Fail!"
        print "Reason:"+jsonResult['message']

def uploadIpaToPgyer(ipaPath):
    print "ipaPath:"+ipaPath
    ipaPath = os.path.expanduser(ipaPath)
    ipaPath = unicode(ipaPath, "utf-8")
    files = {'file': open(ipaPath, 'rb')}
    headers = {'enctype':'multipart/form-data'}
    payload = {'uKey':USER_KEY,'_api_key':API_KEY,'publishRange':'2','isPublishToPublic':'2', 'password':PYGER_PASSWORD}
    print "uploading...."
    r = requests.post(PGYER_UPLOAD_URL, data = payload ,files=files,headers=headers)
    if r.status_code == requests.codes.ok:
        result = r.json()
        parserUploadResult(result)
    else:
        print 'HTTPError,Code:'+r.status_code

def exportArchive():
    exportCmd = "xcodebuild -exportArchive -archivePath %s -exportPath %s -exportOptionsPlist %s" %(ARCHIVEPATH, EXPORT_MAIN_DIRECTORY, EXPORT_OPTIONS_PLIST)
    process = subprocess.Popen(exportCmd, shell=True)
    (stdoutdata, stderrdata) = process.communicate()

    signReturnCode = process.returncode
    if signReturnCode != 0:
        print "export %s failed" %(TARGET)
        return ""
    else:
        return EXPORT_MAIN_DIRECTORY

def buildProject(project):
    archiveCmd = 'xcodebuild -project %s -scheme %s -configuration %s archive -archivePath %s -destination generic/platform=iOS' %(project, TARGET, CONFIGURATION, ARCHIVEPATH)
    process = subprocess.Popen(archiveCmd, shell=True)
    process.wait()

    archiveReturnCode = process.returncode
    if archiveReturnCode != 0:
        print "archive project %s failed" %(project)
        cleanArchiveFile()

def buildWorkspace(workspace):
    archiveCmd = 'xcodebuild -workspace %s -scheme %s -configuration %s archive -archivePath %s -destination generic/platform=iOS' %(workspace, TARGET, CONFIGURATION, ARCHIVEPATH)
    process = subprocess.Popen(archiveCmd, shell=True)
    process.wait()

    archiveReturnCode = process.returncode
    if archiveReturnCode != 0:
        print "archive workspace %s failed" %(workspace)
        cleanArchiveFile()

def xcbuild(options):
    project = options.project
    workspace = options.workspace

    if project is None and workspace is None:
        pass
    elif project is not None:
        buildProject(project)
    elif workspace is not None:
        buildWorkspace(workspace)

    #导出ipa文件
    exportarchive = exportArchive()
    print "~~~~~~~~~~~~~~~~是否上传到蒲公英~~~~~~~~~~~~~~~~"
    print "        1 不上传 (默认)"
    print "        2 上传 "
    isuploadpgyer = raw_input("您的决定：")
    if isuploadpgyer == "2" and exportarchive != "":
        uploadIpaToPgyer(IPAPATH)

    print "~~~~~~~~~~~~~~~~是否上传到AppStore~~~~~~~~~~~~~~~~"
    print "        1 不上传 (默认)"
    print "        2 上传 "
    isuploadappstore = raw_input("您的决定：")
    if isuploadappstore == '2':
        uploadIpaToAppStore()
    else:
        print "~~~~~~~~~~~~~~~~是否删除archive文件~~~~~~~~~~~~~~~~"
        print "        1 保留 (默认)"
        print "        2 删除 "
        iscleararchive = raw_input("您的决定：")
        if iscleararchive == "2":
            cleanArchiveFile()


def main():

    parser = argparse.ArgumentParser()
    parser.add_argument("-w", "--workspace", help="Build the workspace name.xcworkspace.", metavar="name.xcworkspace")
    parser.add_argument("-p", "--project", help="Build the project name.xcodeproj.", metavar="name.xcodeproj")

    options = parser.parse_args()

    print "options: %s" % (options)

    os.system('/usr/libexec/PlistBuddy -c "Set:CFBundleShortVersionString %s" %s' % (VERSION,PLIST_PATH))
    os.system('/usr/libexec/PlistBuddy -c "Set:CFBundleVersion %s" %s' % (BUILD, PLIST_PATH))

    xcbuild(options)

if __name__ == '__main__':
    main()

</pre>


<hr />
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[集成友盟分享中遇到的奇怪的错误]]></title>
    <link href="http://ashen-zhao.github.io/blog/2017/02/14/qi-guai-de-cuo-wu/"/>
    <updated>2017-02-14T13:35:47+08:00</updated>
    <id>http://ashen-zhao.github.io/blog/2017/02/14/qi-guai-de-cuo-wu</id>
    <content type="html"><![CDATA[<h3>开发中遇到的一些看似不起眼的警告，往往却是问题的所在！</h3>

<hr />

<p>这不，这次我就遇到了这个坑，为了提醒自己不要轻易忽略警告，以此文章记录一下，埋坑的艰辛。</p>

<p>我是在集成友盟分享SDK的时候，使用<code>cocoapods</code>导入的友盟分享组件，在命令行敲下pod install只会，安装也完成了，就是出现以下一些警告，我大概浏览了一下，看不出所以然，就没管, 继续在集成。</p>

<!--more-->


<p><i>[!] The <code>ULife [Debug]</code> target overrides the <code>OTHER_LDFLAGS</code> build setting defined in <code>Pods/Target Support Files/Pods-ULife/Pods-ULife.debug.xcconfig'. This can lead to problems with the CocoaPods installation
    - Use the</code>$(inherited)` flag, or
    - Remove the build settings from the target.</p>

<p>[!] The <code>ULife [Release]</code> target overrides the <code>OTHER_LDFLAGS</code> build setting defined in <code>Pods/Target Support Files/Pods-ULife/Pods-ULife.release.xcconfig'. This can lead to problems with the CocoaPods installation
    - Use the</code>$(inherited)` flag, or
    - Remove the build settings from the target.<br/>
</i></p>

<p>直到我开始使用友盟的一些类库时，使用也是没有问题的，可当我编译时，却出现了以下错误信息：</p>

<p><i>Undefined symbols for architecture arm64:
  &ldquo;<em>OBJC_CLASS</em>$_UMSocialManager&rdquo;, referenced from:
      objc-class-ref in AppDelegate.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation) </i></p>

<p>咋一看，还以为是不支持64位呢，可是官方明明写着支持64位的，也就没有去怀疑官方，就开始各种清理缓存，重复编译，各种谷歌，百度，可终究没有可行的办法。去友盟问客服，沟通成本太高，每次掉线，重新连接又是一个新人，也未能解决。</p>

<p>实在没有办法了，我又重新pod update一下，这次发现依然是上面提到的警告信息，这次我没有忽略，而是仔细的看了下，大概知道了，产生此警告的原因是项目 Target 中的一些设置，CocoaPods 也做了默认的设置，如果两个设置结果不一致，就会造成问题。</p>

<p>警告中，提示要想使用cocoapods中的设置，需要在项目中定义<code>PODS_ROOT</code> 和 <code>Other Linker Flags</code>的地方，把他们的值用<code>$(inherited)</code>替换掉。</p>

<p>大致解决办法知道了， 开始在<code>Build Settings</code>中的PODS_ROOT<code>和</code>Other Linker Flags<code>处进行修改，添加一项</code>$(inherited)<code>，Other Linker Flags</code>我这里没有替换掉，而是添加一项，怕我本来的项也是有用的，就没有替换。</p>

<p>最后修改后，我再次编译，竟然通过了，我喜极而泣的写下了这篇文章来记录下这次忽略警告的教训经历。</p>

<hr />

<p>注：在我在网上搜索时，有说，点击项目文件 project.xcodeproj，右键<code>显示包内容</code>，用文本编辑器打开<code>project.pbxproj</code>，删除<code>OTHER_LDFLAGS</code>的地方，保存，回到 Xcode，编译也能通过。这种删除内容的解决办法，我一般不轻易使用的，所以我没有去证实这种做法，若有兴趣，你可以尝试下，不过做好备份哦~~</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[读书，从2017开始]]></title>
    <link href="http://ashen-zhao.github.io/blog/2017/01/23/reading/"/>
    <updated>2017-01-23T11:23:46+08:00</updated>
    <id>http://ashen-zhao.github.io/blog/2017/01/23/reading</id>
    <content type="html"><![CDATA[<h3>诱因</h3>

<p>&emsp;&emsp;最近发生了很多事，让我开始反思自己，让我逐渐认识到自己的不足。工作上，同事一个个能言善辩，应答如流，而我却如同木头一般。生活上，朋友们都在笑谈风声，而我却又如同木头一般。每到这个时候，心情就会有点不好，心情不好我就会去看一些大牛的博客，不看技术的，只看大牛的一些生活记录博客，看大牛写的一些博客，对生活，对工作的见解，很是到位，看来他们也是读了无数的书，才能有如此的见解，让我心生敬佩、向往。</p>

<p>&emsp;&emsp;究其原因就是我读书太少，没有那么多墨水，来表达心中所想。很感谢，哪些能力比较强的人，让我认识自己的不足，至少现在开始我还来得及弥补。</p>

<!--more-->


<h3>读书，从2017开始</h3>

<p>&emsp;&emsp;找到自己缺少什么，就去做什么，是一件简单却又难以坚持的事情。读书，对于我来说，可能比较陌生，我很少去读书，偶尔也就看个短文，对于一本本厚厚的书籍，我是没看过几本的。著名的四大名著，我是一页都没看过的，这可能是种遗憾吧，但这也是个警钟，每每想起都会让我觉得，读书，读书，读书的重要性。 之说以在这里写下这边文章，我也是想监督下自己，不再向以往那样，只是嘴皮子上说说而已，这次要拿出实际行动来读书。</p>

<p>读书，从2017年开始。</p>

<h3>读书计划</h3>

<p>1.每两个月或者一个月读一本书<br/>
2.读完一本做阅后感<br/>
3.前4个月，可以不用严格执行第一条（刚开始不能太多要求）<br/>
4.读书方式，可选择电子书、纸质书等</p>

<h3>读书目的</h3>

<p>丰富自己的知识体系，提高自己的表达能力以及沟通能力，摆脱被淘汰的可能，能做到自己营销，摆脱社交恐惧症。。。。</p>

<hr />

<p>随时随地随便谁。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[探索Xcode8编译为什么那么慢？]]></title>
    <link href="http://ashen-zhao.github.io/blog/2016/12/21/xcode8build/"/>
    <updated>2016-12-21T10:12:58+08:00</updated>
    <id>http://ashen-zhao.github.io/blog/2016/12/21/xcode8build</id>
    <content type="html"><![CDATA[<h3>背景</h3>

<p>随着<code>Xcode8</code>和<code>swift3.0</code>的正式到来，我开始着手将<code>swift2.3</code>的项目转到<code>swift3</code>（至于转换过程，这里不多做介绍，Xcode自带的转换工具，基本可以转换80%左右，剩下的自己慢慢调试即可。）但是，转到swift3只会，在用Xcode8编译，发现编译过程变得非常慢，哪怕打一个空格，都要重新编译很久。于是在网上查找解决办法，查找了半天各种方法全用，发现于事无补。<br/>
&emsp;&emsp;有什么加一个<code>HEADERMAP_USES_VFS = YES</code>（）<a href="http://www.cnblogs.com/qqsscc/p/6044234.html">这是地址，反正这个对我没用，感兴趣的话自己试试</a></p>

<h5>针对这种情况，我就自己探索，出发点是排查哪些文件，哪些方法导致编译变慢？</h5>

<h3>探索Xcode编译，在哪些地方可以看到编译文件过程</h3>

<hr />

<p>通过多次编译查看，发现在Xcode左边栏，最后一个选项，是每次的编译运行等记录， 每行记录中都会有每次编译的文件编译记录。如下图</p>

<!--more-->  


<p><img src="http://ashen-zhao.github.io/images/build1.png" alt="图1" /></p>

<p>再次查看正在编译的一条记录(正在编译的记录后面有一个转圈圈的”菊花“)，发现有图中1、2两种标识， 一个绿色✅说明，这是编译完成了，另一个是灰色→箭头，说明是正在编译；此时发现灰色一直停留在这里，指向图中的文件，左边的菊花一直转个不停， 编译卡住了。这样一来就找到编译是什么文件导致的那么慢。</p>

<p><img src="http://ashen-zhao.github.io/images/build2.png" alt="图2" /></p>

<h3>排查文件中哪些代码导致的编译卡住？</h3>

<hr />

<p>排查的方法，采用比较笨的方法，暴力注释方法：<strong><em>就是注释找到卡住的文件中的所有方法里的代码，不要注释方法，再次编译，此时发现该文件很快通过编译，然后在依次解开部分方法注释，再次编译，直到发现解开某个方法的注释后，编译再次卡住，那就说明那个方法中的代码写的有问题，然后在依次注释，解开注释，排查方法中的某一行代码的问题。</em></strong>经过一番排查，我找到了我代码中卡住的部分代码，如下图红色圈中的代码</p>

<p><img src="http://ashen-zhao.github.io/images/build3.png" alt="图3" /></p>

<p><font color=red>在字典中的key对应的value，没有给直接的值，而是给出一个表达式，这样会导致Xcode8的编译速度极其慢，不知道为什么会出现这样的问题，之前的Xcode版本是没有的。</font></p>

<p>找到问题所在，解决问题就简单了，于是修改代码如下图：</p>

<p><img src="http://ashen-zhao.github.io/images/build4.png" alt="图4" /></p>

<p>修改之后，再次编译，重新回到了快速编译的时代了，再也不用等上5-10分钟不等了。</p>

<p>  以上过程，是针对我遇到的问题而言的，不知道是否存在普遍性，如若你也遇到，刚好看了我的文章，也解决了问题，那就会心一笑吧，如若你也遇到了，但是没有解决问题，也请你会心一笑吧。<br/>
     <a href="https://forums.developer.apple.com/thread/62737">这是苹果开发者提到的Xcode8编译超慢的问题，我看了下，也做了对应修改，发现对我并没有什么用， 感兴趣的话进去看看吧</a></p>

<p>有时候自己慢慢去探索出问题的所在，也是很不错的体验。</p>

<hr />

<h3>后知后觉</h3>

<hr />

<p>后来我知道了，也可以通过，查看具体的swift函数编译时间来定位哪个函数卡住了，而不用<code>暴力注释法</code>.<br/>
首先要到Build Settings 给 Other Swift Flags  添加一项<code>
-Xfrontend -debug-time-function-bodies</code> <br/>
就可以查看编译通过的文件中的函数编译时间，找到绿色✅的文件的那一行，在最后面有一个图标，点击展开具体内容，向下移动就会看到每个函数执行的具体时间。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[iOS 中的网络加密]]></title>
    <link href="http://ashen-zhao.github.io/blog/2016/08/05/https/"/>
    <updated>2016-08-05T17:28:40+08:00</updated>
    <id>http://ashen-zhao.github.io/blog/2016/08/05/https</id>
    <content type="html"><![CDATA[<h2>iOS 中的网络加密</h2>

<hr />

<h5>引言：公司的接口一般会两种协议的，一种HTTP，一种HTTPS的，HTTP 只要请求，服务器就会响应，如果我们不对请求和响应做出加密处理，所有信息都是会被检测劫持到的，是很不安全的，客户端加密可以使用本文这套工具类进行处理。但是不论在任何时候，都应该将服务置于HTTPS上，因为它可以避免中间人攻击的问题，还自带了基于非对称密钥的加密通道。</h5>

<h3>HTTPS交互原理</h3>

<p>简答说，HTTPS 就是 HTTP协议加了一层SSL协议的加密处理，SSL 证书就是遵守 SSL协议，由受信任的数字证书颁发机构CA（如GlobalSign，wosign），在验证服务器身份后颁发，这是需要花钱滴，签发后的证书作为公钥一般放在服务器的根目录下，便于客户端请求返回给客户端，私钥在服务器的内部中心保存，用于解密公钥。</p>

<h4>HTTPS 客户端与服务器交互过程：</h4>

<p>1）客户端发送请求，服务器返回公钥给客户端；</p>

<p>2）客户端生成对称加密秘钥，用公钥对其进行加密后，返回给服务器；</p>

<p>3）服务器收到后，利用私钥解开得到对称加密秘钥，保存；</p>

<p>4）之后的交互都使用对称加密后的数据进行交互。</p>

<!--more-->


<h3>证书</h3>

<p>简单说，证书有两种，一种是正经的：</p>

<p>CA颁发的证书</p>

<p>一种是不正经的：</p>

<p>自己生成签发的证书</p>

<h3>我们需要做什么</h3>

<p>如果遇到正经的证书，我们直接用AFNetworking 直接请求就好了，AFNetworking 内部帮我们封装了HTTPS的请求方式，但是大部分公司接口都是不正经的证书，这时需要我们做以下几步：</p>

<p>1）将服务器的公钥证书拖到Xcode中</p>

<p>2）修改验证模式</p>

<pre><code>manager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey];
</code></pre>

<h3>原理</h3>

<p>简单来说，就是你本可以修改AFN这个设置来允许客户端接收服务器的任何证书，但是这么做有个问题，就是你无法验证证书是否是你的服务器后端的证书，给中间人攻击，即通过重定向路由来分析伪造你的服务器端打开了大门。</p>

<pre><code>AFSecurityPolicy *securityPolicy = [AFSecurityPolicy defaultPolicy];
securityPolicy.allowInvalidCertificates = YES;
</code></pre>

<h3>解决方法</h3>

<p>AFNetworking是允许内嵌证书的，通过内嵌证书，AFNetworking就通过比对服务器端证书、内嵌的证书、站点域名是否一致来验证连接的服务器是否正确。由于CA证书验证是通过站点域名进行验证的，如果你的服务器后端有绑定的域名，这是最方便的。将你的服务器端证书，如果是pem格式的，用下面的命令转成cer格式</p>

<pre><code>openssl x509 -in &lt;你的服务器证书&gt;.pem -outform der -out server.cer
</code></pre>

<p>然后将生成的server.cer文件，如果有自建ca，再加上ca的cer格式证书，引入到app的bundle里，AFNetworking在</p>

<pre><code>AFSecurityPolicy *securityPolicy = [AFSecurityPolicy AFSSLPinningModeCertificate];
</code></pre>

<p>或者</p>

<pre><code>AFSecurityPolicy *securityPolicy = [AFSecurityPolicy AFSSLPinningModePublicKey];
</code></pre>

<p>情况下，会自动扫描bundle中.cer的文件，并引入，这样就可以通过自签证书来验证服务器唯一性了。</p>

<h3>AFSecurityPolicy三种验证模式</h3>

<p>1）AFSSLPinningModeNone
这个模式表示不做SSL pinning，
只跟浏览器一样在系统的信任机构列表里验证服务端返回的证书。若证书是信任机构签发的就会通过，若是自己服务器生成的证书就不会通过。</p>

<p>2）AFSSLPinningModeCertificate
这个模式表示用证书绑定方式验证证书，需要客户端保存有服务端的证书拷贝，这里验证分两步，第一步验证证书的域名有效期等信息，第二步是对比服务端返回的证书跟客户端返回的是否一致。</p>

<p>3）AFSSLPinningModePublicKey
这个模式同样是用证书绑定方式验证，客户端要有服务端的证书拷贝，
只是验证时只验证证书里的公钥，不验证证书的有效期等信息。只要公钥是正确的，就能保证通信不会被窃听，因为中间人没有私钥，无法解开通过公钥加密的数据。</p>

<hr />

<p>此文章转载自：<a href="http://charsdavy.github.io/2016/06/15/ios-network-encrypt">http://charsdavy.github.io/2016/06/15/ios-network-encrypt</a> <br/>
感谢原作者让我们又学到了知识。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[二维码扫描识别]]></title>
    <link href="http://ashen-zhao.github.io/blog/2016/07/20/qrcode/"/>
    <updated>2016-07-20T14:31:51+08:00</updated>
    <id>http://ashen-zhao.github.io/blog/2016/07/20/qrcode</id>
    <content type="html"><![CDATA[<p>&emsp;最近忙于工作，工作之余也在学习swift，在github上开源了正在开发维护的swift项目<a href="https://github.com/ashen-zhao/baisiapp">模仿的百思不得姐</a>；不过今天不是来介绍这个开源项目的，而是来给大家介绍一个很简单的功能之 iOS 二维码扫描识别；</p>

<h5>我将该功能进行了简单的封装，只需要简单调用就可以实现；</h5>

<h5>封装文件：</h5>

<p><code>QRCodeManager.h</code>该文件是封装的二维码识别功能</p>

<h5>调用方法：</h5>

<pre><code>    _qr = [[QRCodeManager alloc] init];
     _qr.delegate = self;
    [_qr configureManager:self.view];
</code></pre>


<p></p>

<h5>服从协议<code>QRCodeManagerDelegate</code>实现代理方法：</h5>

<p><code>- (void)qrCodeResult:(NSString *)result</code> ，result即为扫描识别到的二维码信息了，就是这么简单。</p>

<h4>Demo示例图</h4>

<p><img src="http://ashen-zhao.github.io/images/qrcode.gif" alt="二维码扫描识别" /></p>

<h4>Demo源码地址：</h4>

<p><a href="https://github.com/ashen-zhao/asqrcode">二维码扫描识别Demo下载地址</a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[让UIImageView显示Gif图]]></title>
    <link href="http://ashen-zhao.github.io/blog/2016/04/14/gifimageview/"/>
    <updated>2016-04-14T13:57:05+08:00</updated>
    <id>http://ashen-zhao.github.io/blog/2016/04/14/gifimageview</id>
    <content type="html"><![CDATA[<p>&emsp;各位同学们，这次给大家分享一个小工具，可以解决你在开发过程中，需要显示Gif图片的需求；由于太过于简单，我这里就不多说了；有需要的同学，请前往<a href="https://github.com/ashen-zhao/asGifImageView">https://github.com/ashen-zhao/asGifImageView</a>进行下载，不需要的同学也可以去Star，留着以后使用，最后，记得关注我哦，哈哈😄；</p>

<h2>接下来，简单写一下如何使用该工具</h2>

<h4>示例图</h4>

<p><img src="http://ashen-zhao.github.io/images/gifView.gif" alt="啊神gifUIImageView" /></p>

<h4>功能说明：</h4>

<p>这是一个UIImageView的分类，可以让UIImageView支持显示本地Gif以及网络Gif图片。</p>

<h4>使用说明</h4>

<p>1.导入分类头文件 <code>#import "UIImageView+ASGif.h"</code><br/>
2.调用<br/>
&emsp;a.显示本地gif图片 <br/>
    <code>[self.gifImgV showGifImageWithData:[NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"abc" ofType:@"gif"]]];</code><br/>
&emsp;b.显示网络gif图片<br/>
       <code>[self.gifImgV showGifImageWithURL:[NSURL URLWithString:@"http://ww1.sinaimg.cn/large/85cccab3gw1etdi67ue4eg208q064n50.gif"]];</code></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[iOS之接地气的移动支付]]></title>
    <link href="http://ashen-zhao.github.io/blog/2016/01/26/pay/"/>
    <updated>2016-01-26T11:15:35+08:00</updated>
    <id>http://ashen-zhao.github.io/blog/2016/01/26/pay</id>
    <content type="html"><![CDATA[<h3>iOS 移动支付之种类</h3>

<p>iOS 端的移动支付，大概包括：支付宝支付、微信支付、银联卡支付、paypal支付，现在又多出一个Apple pay支付；</p>

<h3>如何集成这些种类的支付方式</h3>

<p>谈及如何集成这些支付方式，面对各种支付方式的SDK以及Demo写的详细的完美无缺，我还真不如还如何去写，这里我就接地气的写写，写的不好请勿喷哦☺！</p>

<h3>支付宝支付</h3>

<h3>大致有以下步骤：</h3>

<h4>1.向支付宝申请, 与支付宝签约，获得商户PID（partner）和账号ID（seller）和私钥(privateKey)</h4>

<p>注：*这一步，一般公司会搞定的，这里只是让你知道来龙去脉☺<br/>
&emsp; 没有支付宝账号的同学，可以<a href="https://memberprod.alipay.com/account/reg/index.htm">点击这里注册账号</a>; <br/>
&emsp; 已经有支付宝账号的同学<a href="https://b.alipay.com/order/productDetail.htm?productId=2015110218010538">点击这里申请移动支付</a><br/>
申请签约有个门槛比较难，就是不管你是个人还是企业，都需要营业执照，这点有点蛋疼，不过人家也是为了有质量的管理申请者嘛，可以理解，我这里没有营业执照，申请工作就死在了摇篮里，不过大致流程，我基本弄清楚了，<strong>不过作为开发者，这申请工作就不用多关心了，一般公司都会有申请过的</strong>，我这里写出来也就是让我们开发者也大概知道流程，而不是直接就是用，只知去向，不知来龙。  <br/>
申请签约成功后，就可以查看 PID（partner）和账号ID（seller）和私钥(privateKey) ，<a href="https://b.alipay.com/order/serviceIndex.htm">查看地址点击这里</a> 进行登录，点击下图中的查询PID和Key;<br/>
<img src="http://ashen-zhao.github.io/images/pay01.png" alt="Pay" /></p>

<!--more-->


<p>但是这里查询到的Key 是公钥，不是私钥，你到底该怎么弄私钥呢？同学们，不用急，支付宝文档写的还是比较清楚的，<a href="https://doc.open.alipay.com/doc2/detail.htm?spm=a219a.7629140.0.0.cxzipP&amp;treeId=58&amp;articleId=103242&amp;docType=1">点击这里可以查看RSA私钥及公钥生成</a></p>

<p>这里文档给出了两种平台下的生产方式，我们既然是iOS 开发者，那就选择Linux用户生产的方式吧，可以直接在Mac的终端敲这些命令；
<img src="http://ashen-zhao.github.io/images/pay02.png" alt="啊神支付" /><br/>
敲过这些命令后，会在本地生产两个文件，分别是私钥和公钥文件<br/>
在命令行敲入（以行为单位）<br/>
$cd ~/<br/>
$open .  //打开文件的存放位置<br/>
想要查看文件内容，还需要使用命令<br/>
$cat rsa_private_key.pem  //会在终端显示文件中的内容，这就是私钥<br/>
到这里，第一步基本上就可以了，具体还需要自己动手试试，不然还是会一头雾水。</p>

<h4>2.下载支付宝SDK以及Demo</h4>

<p>这一步，没啥好说的，给个地址就行<a href="https://doc.open.alipay.com/doc2/detail.htm?treeId=54&amp;articleId=104509&amp;docType=1">SDK以及Demo下载地址</a></p>

<h4>3.集成SDK到工程中（生成订单信息,签名加密）</h4>

<h5>支付宝官方集成文档</h5>

<p>集成支付宝SDK的步骤，这里是官方给出的<a href="https://doc.open.alipay.com/doc2/detail.htm?spm=a219a.7629140.0.0.SiPSmP&amp;treeId=59&amp;articleId=103676&amp;docType=1">集成文档</a>, 按照步骤集成总是会出错，这不是我们脑子不行，而是官方毕竟是官方。<br/>
查看支付宝给出的Demo，会发现这些文件必须要加到项目中：
<img src="http://ashen-zhao.github.io/images/pay05.png" alt="啊神" /><br/>
其中小方框中的为必须加入，而除了小方框以外的，那就要看你们后台人员是否将签名成功字符串格式化的订单字符串，给你传到前端来，如果没有，那就必须你自己在前端处理； 按理说，这些应该由后台来处理，为了订单信息的安全，以及前端业务的轻运行，都该有后端来处理（注：这点不懂，不要紧，后面还会根据代码在进行讲解;</p>

<h5>集成中可能遇到的错误</h5>

<p>1）Cannot find interface declaration for &lsquo;NSObject&rsquo;<br/>
<img src="http://ashen-zhao.github.io/images/pay03.png" alt="啊神" /><br/>
解决方案：a. 可以在报错的文件中加入<code>#import &lt;Foundation/Foundation.h&gt;</code><br/>
b. 可以建个pch文件加入</p>

<pre>`
#ifdef __OBJC__
#import UIKit/UIKit.h
#import Foundation/Foundation.h
#endif
`</pre>


<p></p>

<p>2)提示找不到 openssl/asn1.h 文件<br/>
<img src="http://ashen-zhao.github.io/images/pay06.png" alt="啊神" /><br/>
解决方案：Build Settings &ndash;> Search Paths &ndash;> Header Search paths:$(PROJECT_DIR)/ASPayDemo/Alipay<br/>
<img src="http://ashen-zhao.github.io/images/pay07.png" alt="啊神" /></p>

<p>3)_CNCopyCurrentNetworkInfo,referenced from:<br/>
<img src="http://ashen-zhao.github.io/images/pay08.png" alt="啊神" /><br/>
解决方案：添加SystemConfiguration.framework</p>

<p><img src="http://ashen-zhao.github.io/images/pay09.png" alt="啊神" /></p>

<h4>部署代码</h4>

<pre>
<code>

    NSString *partner = @""; //PID

    NSString *seller = @""; //收款账户，手机号或者邮箱
   
    NSString*privateKey= @"";// 私钥
    
    if ([partner length] == 0 ||
        [seller length] == 0 ||
        [privateKey length] == 0)
    {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示"
                                                        message:@"缺少partner或者seller或者私钥。"
                                                       delegate:self
                                              cancelButtonTitle:@"确定"
                                              otherButtonTitles:nil];
        [alert show];
        return;
    }
    
    Order *order = [[Order alloc] init];
    order.partner = partner;
    order.seller = seller;
    order.tradeNO = @"20160324012412412"; //订单ID（由商家自行制定）
    order.productName = @"iOS 高级教程"; //商品标题
    order.productDescription = @"这是一本关于iOS的一本高级教程书"; //商品描述
    order.amount = @"0.1"; //商品价格
    order.notifyURL = @"http://www.devashen.com/Notify/Alipay/"; //回调URL
    
    order.service = @"mobile.securitypay.pay";
    order.paymentType = @"1";
    order.inputCharset = @"utf-8";
    order.itBPay = @"30m";
    order.showUrl = @"m.alipay.com";
    
    NSString *appScheme = @"alisdkdemo";
    
    //将商品信息拼接成字符串   该方法支付宝已经封好
    NSString *orderSpec = [order description];
    
    
    //获取私钥并将商户信息签名,外部商户可以根据情况存放私钥和签名,只需要遵循RSA签名规范,并将签名字符串base64编码和UrlEncode
    id<DataSigner> signer = CreateRSADataSigner(privateKey);
    //调用签名
    NSString *signedString = [signer signString:orderSpec];
    
    
    
    
    //将签名成功字符串格式化为订单字符串,请严格按照该格式
    NSString *orderString = nil;
    if (signedString != nil) {
        orderString = [NSString stringWithFormat:@"%@&sign=\"%@\"&sign_type=\"%@\"",
                       orderSpec, signedString, @"RSA"];
        
        
        //***************上面提到好的后台，会把订单字符串直接传给我们，而我们要做的其实也就只剩下这一步了********************/
        [[AlipaySDK defaultService] payOrder:orderString fromScheme:appScheme callback:^(NSDictionary *resultDic) {
            if ([[resultDic objectForKey:@"resultStatus"] isEqualToString:@"9000"]) {
                //9000为支付成功
                
            }
            
        }];
    }

</code></pre>


<p>
看代码，如果后台将签名成功字符串格式化的订单字符串，给你传到前端来，那我们就只需要做很少的工作就可以了，只需要直接处理订单字符串即可：</p>

<pre><code>
        [[AlipaySDK defaultService] payOrder:orderString fromScheme:appScheme callback:^(NSDictionary *resultDic) {
            if ([[resultDic objectForKey:@"resultStatus"] isEqualToString:@"9000"]) {
                //9000为支付成功
                
            }
            
        }];
</code></pre>


<p>
最后，千万别忘了，在Appdelegate中，处理支付宝客户端返回url处理方法, 少了这一步，支付宝SDK的回调方法是不会执行的：</p>

<pre><code>
- (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
  sourceApplication:(NSString *)sourceApplication
         annotation:(id)annotation {
   //跳转支付宝钱包进行支付，处理支付结果
        [[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary *resultDic) {
            NSLog(@"result = %@",resultDic);
        }];
    return YES;
}
</code></pre>


<p>
到这里，支付宝支付基本上完成， 迫不及待的你，赶紧去试验试验吧， 别忘了给你们相关负责人要对应的PID、收款账号、以及私钥，当然如果后台直接传给你订单字符串的话，你可以直接给后台要接口了，置于PID什么的你就不用管了。</p>

<h5>相关连接</h5>

<p><a href="https://github.com/ashen-zhao/aspay">本文章对应的Demo, 包含后端是、否给你订单字符串的两种处理</a></p>

<p><a href="https://doc.open.alipay.com/doc2/detail.htm?spm=a219a.7629140.0.0.AIe1BQ&amp;treeId=59&amp;articleId=103563&amp;docType=1">支付宝移动支付SDK官方文档</a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[仿照微博、微信弹出ActionSheet样式]]></title>
    <link href="http://ashen-zhao.github.io/blog/2016/01/22/assheet/"/>
    <updated>2016-01-22T15:08:16+08:00</updated>
    <id>http://ashen-zhao.github.io/blog/2016/01/22/assheet</id>
    <content type="html"><![CDATA[<p>&emsp;iOS 开发中，很多应用都会用到从屏幕底部弹出的UIActionSheet, 但是使用的过程中，总感觉系统的样式怪怪的，或者与自己开发的App的UI不是很协调，总之与自己的App搭配就一个字：丑。 说起ActionSheet样式，应该来看看主流的微博与微信是什么样式的；</p>

<p><img src="http://ashen-zhao.github.io/images/assheet02.PNG" width="200" height="370" alt="微信">
<img src="http://ashen-zhao.github.io/images/assheet01.PNG" width="200" height="370" alt="微博"></p>

<p>看上去的确挺自然，一点也不像系统自带的，给人的感觉就是不协调，不协调的</p>

<!--more-->


<p><img src="http://ashen-zhao.github.io/images/assheet03.png" width="200" height="370" alt="微信"></p>

<p>看吧,系统的与人家设计的，看上去就逊色许多。
出于比较喜欢微博、微信这种设计，就自己动手鼓弄着也写了个<a href="https://github.com/Ashen-Zhao/ASSheet">工具类</a>，为以后使用做准备，使用起来很简单，只需传入titles 数组，以及实现一个Block 点击回调，就可以很快的实现像微博微信那样的样式，先看看效果图吧：</p>

<p><img src="http://ashen-zhao.github.io/images/assheet04.gif" alt="啊神ActionSheet" /></p>

<h3>我是如何实现的</h3>

<p>&emsp;写一个继承自UIView的类，用这个view 来做为弹出后的幕布（也就是半透明的背景），然后给这个view 添加一个单击手势，手势方法就是讲该view移除隐藏的方法，然后将次view 背景色设置成半透明, 用 <code>[self setBackgroundColor:[UIColor colorWithWhite:0.5 alpha:0.5]]</code> 来设置半透明背景色。<br/>
&emsp;然后再定义个UIview *titleBgkView属性，该view 用来当titles 的幕布， 随后创建该view， 并且将此view 的frame 根据titles 的多少进行动态调整，我这里重写了大幕布的init 方法<code>- (instancetype)initWithFrame:(CGRect)frame titleArr:(NSArray *)titleArr</code> 传入titles 数组。 <br/>
&emsp;再然后，根据传入的titles 进行创建title按钮，将创建的按钮添加到titleBgkView 上。<br/>
噗，我这是写的啥，我还是直接上代码吧，对不住各位了，实在写不下去了，程序员嘛还是直接看代码来的最直接，对吧。
这是我的.m 文件实现代码</p>

<pre> <code> 
- (instancetype)initWithFrame:(CGRect)frame titleArr:(NSArray *)titleArr {
    self = [super initWithFrame:frame];
    size = [UIScreen mainScreen].bounds.size;
    [self setBackgroundColor:[UIColor colorWithWhite:0.5 alpha:0.5]];
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hiddenSheet)];
    [self addGestureRecognizer:tap];
    [self makeBaseUIWithTitleArr:titleArr];
    
    return self;
}

- (void)makeBaseUIWithTitleArr:(NSArray *)titleArr{
   
    self.bgkView = [[UIView alloc] initWithFrame:CGRectMake(0, size.height, size.width, titleArr.count * 50 + 55)];
    _bgkView.backgroundColor = [UIColor colorWithRed:0xe9/255.0 green:0xe9/255.0 blue:0xe9/255.0 alpha:1.0];
    [self addSubview:_bgkView];

    CGFloat y = [self createBtnWithTitle:@"取消" origin_y: _bgkView.frame.size.height - 50 tag:-1 action:@selector(hiddenSheet)] - 55;
    for (int i = 0; i < titleArr.count; i++) {
        y = [self createBtnWithTitle:titleArr[i] origin_y:y tag:i action:@selector(click:)];
    }
    [UIView animateWithDuration:0.3 animations:^{
        CGRect frame = _bgkView.frame;
        frame.origin.y -= frame.size.height;
        _bgkView.frame = frame;
    }];
   
}

- (CGFloat)createBtnWithTitle:(NSString *)title origin_y:(CGFloat)y tag:(NSInteger)tag action:(SEL)method {
    UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
    [btn setTitle:title forState:UIControlStateNormal];
    btn.frame = CGRectMake(0, y, size.width, 50);
    btn.backgroundColor = [UIColor whiteColor];
    btn.tag = tag;
    [btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    [btn addTarget:self action:method forControlEvents:UIControlEventTouchUpInside];
    [_bgkView addSubview:btn];
    return y -= tag == -1 ? 0 : 50.4;
}
- (void)hiddenSheet {
    [UIView animateWithDuration:0.3 animations:^{
        CGRect frame = _bgkView.frame;
        frame.origin.y += frame.size.height;
        _bgkView.frame = frame;
    }];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self removeFromSuperview];
    });
}

- (void)click:(UIButton *)btn {
    if (self.Click) {
        _Click(btn.tag);
    }
}

</code> </pre>


<p></p>

<p>这是.h 文件代码</p>

<pre> <code> 
@property (nonatomic, copy) void (^Click)(NSInteger clickIndex);
- (instancetype)initWithFrame:(CGRect)frame titleArr:(NSArray *)titleArr;
- (void)hiddenSheet;

</code></pre>


<p></p>

<p>看吧，这多简单方便，有代码直接上，废话少说，程序员对代码的情结不容小觑，哼哈哈。</p>

<p>这里我也把使用的代码给贴出来吧，慢慢观察，仔细看，哈哈，使用起来很容易</p>

<pre> <code>
- (IBAction)showSheet:(id)sender {
    AS_Sheet *a = [[AS_Sheet alloc] initWithFrame:self.view.bounds titleArr:@[@"从手机相册选择", @"拍照", @"小视频"]];
    __weak typeof(a) weakA = a;
    a.Click = ^(NSInteger clickIndex) {
        switch (clickIndex) {
            case 0:
                NSLog(@"相册选择");
                break;
            case 1:
                NSLog(@"拍照");
                break;
            case 2:
                NSLog(@"小视频");
                break;
            default:
                break;
        }
        [weakA hiddenSheet];
    };
    [self.navigationController.view addSubview:a];
}

</code></pre>


<p></p>

<p>最后，老规矩我还是把<a href="https://github.com/Ashen-Zhao/ASSheet">Demo附上</a>，以供辅助参考，Demo中包含swift版本和OC版本</p>
]]></content>
  </entry>
  
</feed>
