0%

前言


在项目中,当我们想要设置View的阴影效果时,可以通过shadow*相关方法实现,如:

1
2
3
self.layer.shadowOffset = CGSizeMake(4, -2);
self.layer.shadowOpacity = 0.5;
self.layer.shadowColor = [[UIColor blackColor] colorWithAlphaComponent:0.5].CGColor;

实现效果如下:

如上实现方式,有些情况下,你并不会发现有什么问题,但是一旦将其用在如UITableViewCellUICollectionViewCell等时,你会发现,滑动时会导致大量掉帧的情况,其主要原因为,shadow*方法的使用将导致Core Animation进行离屏渲染,为了确定这一点,可以通过Instruments工具,选择Core Animation模板,选择开启Color Offscreen-Rendered Yellow Debug选项,当我们滑动CollectionView时,其帧率如下,产生了大量掉帧的情况,且正如我们所料,使用shadow*方法的视图被标黄,既使用了离屏渲染。

帧率情况如上,可以看到丢帧率很高。

阅读全文 »

源码分析


Alamofire是对URLSession的封装,针对普通请求,上传、下载等操作,提供对应的Request,其对象关系如下:

每一个Request关联一个TaskDelegateTaskDelegate用来处理URLSessionTask使用过程中的网络回调,TaskDelegate有一个queue成员,用来执行task完成后的回调处理,completionHandler默认会在主线程回调。Alamofire有一个SessionDelegate,对Session的所有网络回调做处理,并调用每一个taskTaskDelegate,正因为SessionDelegate只有一个实例,所以会涉及到线程安全的问题,对某些关键属性需要做竟态处理,如管理Request的字典。委托处理流程如下图所示:

阅读全文 »

类型引用


在开发中,我们经常用到实例的类型,希望实例与其真正的对象类型关联,既面向对象中的多态性。接下来将通过一个例子来进行讨论,比如,定义一个Dog类,用来描述狗,如下:

1
2
3
4
5
6
7
8
class Dog {
class var whatDogsSay : String {
return "Woof"
}
func bark() {
print(Dog.whatDogsSay)
}
}

Dog类的bark为狗叫所定义的方法,实现中直接硬编码Dog.whatDogsSay,这种方法会很不灵活,尤其是其如果作为父类被子类时。

Swift中,可以使用type(of:)方法来访问对象实际的类型,既会返回实例对象真正的类型,所以,可以对之前的Dog进行改进,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Dog {
class var whatDogsSay : String {
return "Woof"
}
func bark() {
print(type(of:self).whatDogsSay)
}
}

class NoisyDog : Dog {
override class var whatDogsSay : String {
return "Woof woof woof"
}
}

如上定义,结果如下:

1
2
let nd = NoisyDog()
nd.bark() // Woof woof woof

如果向NoisyDog实例发送bark消息,结果为”Woof woof woof”。这就是type(of:)方法的作用,他会指向实例真正的类型。self表示实例,类型为NoisyDog,所以type(of:self)返回NoisyDog类,所以会调用NoisyDog类的whatDogsSay类属性。

有时候,需要传递一个对象类型作为参数:

  • 声明对象的类型时,可以使用类型名加.再加关键字Type
  • 如果使用一个对象作为值时,比如,将类型赋值给一个变量或者作为参数值传递给函数时,可以使用类型名加self关键字,或者type(of:)方法。
阅读全文 »

HTTPS页面混合不安全的HTTP请求


在启用HTTPS页面时,如果出现HTTP请求,那么浏览器会报错,如下:

1
Mixed Content: The page at ‘https://www.taobao.com/‘ was loaded over HTTPS, but requested an insecure image ‘http://g.alicdn.com/s.gif’. This content should also be served over HTTPS.

既浏览器会Block掉不安全的HTTP请求,所以解决方法有三种:

  1. 最简单的,将HTTP替换为HTTPS
  2. 去掉URL中的http://https://,将其替换为//,这样,浏览器就可以根据当前页面的请求方式来动态切换了。
  3. 如果涉及到第三方的资源,无法直接修改源代码,如腾讯公益404的JavaScript代码如下,document.write函数写入两个JavaScript文件,而这两个文件中包含了HTTP的请求。这个时候,我们可以在<head>中添加<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">,浏览器会在加载HTTP资源时自动替换成HTTPS请求。
1
2
3
var _base = '//qzone.qq.com/gy/404/';
document.write('<scri' + 'pt type="text/javascript" src="' + _base + 'data.js" charset="utf-8"></sc' + 'ript>');
document.write('<scri' + 'pt type="text/javascript" src="' + _base + 'page.js" charset="utf-8"></sc' + 'ript>');

crontab执行Shell脚本时的工作目录


由于工作需要,创建了一个crontab定时任务,用来在每天固定时间执行一个Shell脚本,在Shell脚本中,有对该脚本所在目录的相关文件进行操作的逻辑,在一开始实现时,对当前目录的文件操作时都是使用的相对目录,即./*。在终端直接sh执行时没有任何问题,正常结束,而一旦在crontab中定时执行时,就出现问题,如提示file not found等错误。

解决工作目录问题


出现问题后,我在脚本中试着打印出crontab执行时的当前目录,如curPath=$(pwd),执行后发现,打印出的结果为$HOME的目录,而非脚本所在的原始目录,这就造成了在脚本中使用相对路径时出现找不到的情况。

找到问题后,解决方法有两个:

  1. 将相对路径替换为绝对路径。(ps:如脚本中包含某些Shell命令,且命令的某些参数为默认当前目录的,都需要显式的给出绝对路径)
  2. 在操作相对路径之前,使用cd /....../,在执行脚本时强制进入到该目录。

附录


系统在执行定时任务时,是不会加载任何环境变量的,所以当脚本需要Java或其他环境变量时,可以通过在脚本中添加source /etc/profile命令来使配置生效。

HTTP Keep-Alive


HTTPKeep-Alive,是HTTP 1.1默认的功能(HTTP 1.0可以在请求头中设置Keep-Alive来显式开启),其表示持久连接,以前我们所使用的HTTP请求,当发出请求并接收完响应后,将关闭TCP连接,所以,如果我们短时间内进行大量的HTTP请求的话,会导致过多的TCP连接建立、关闭消耗.

HTTP Keep-Alive vs TCP KeepAlive


注意,我们目前说的都是HTTPKeep-Alive,其实,TCP也有KeepAlive的概念,它解决的主要问题是,当连接建立后,如果没有数据传输,或者隔一段时间才发送一次数据时,如何来确定Client是否在线,连接是否需要保持,TCP解决方法为,当超过一段时间后,TCP会自动发送一个数据为空的报文给Client,如果对方回应了,则连接继续保持,否则,在重试多次无果后将关闭连接。

Pipeline


HTTP 1.1引入了Pipeline,其基于Keep-Alive,既利用一个连接做多次请求,当Client提交多个请求时,不需要等第一个请求的响应接收完就能发起第二个请求,既实现类似于流水作业的功能。目前主流服务器都支持Keep-AlivePipeline

使用NSURLSession开启Keep-Alive、Pipeline


阅读全文 »

问题


  1. 命令行执行Job任务时,出现如下问题,原因为MacOS系统的文件系统大小写不敏感,导致在unjar包时报错,有命名冲突。

    1
    2
    3
    4
    5
    6
    Exception in thread "main" java.io.IOException: Mkdirs failed to create /var/folders/zz/zyxvpxvq6csfxvn_n0000000000000/T/hadoop-unjar3745345762036287746/license
    at org.apache.hadoop.util.RunJar.ensureDirectory(RunJar.java:128)
    at org.apache.hadoop.util.RunJar.unJar(RunJar.java:104)
    at org.apache.hadoop.util.RunJar.unJar(RunJar.java:81)
    at org.apache.hadoop.util.RunJar.run(RunJar.java:209)
    at org.apache.hadoop.util.RunJar.main(RunJar.java:136)

    解决方法为执行如下命令,删除jar文件中的这两个文件。

    1
    2
    zip -d Documents/Test.jar LICENSE
    zip -d Documents/Test.jar META-INF/LICENSE
  2. 使用Eclipse导出可供Hadoop执行的jar包时,导出的类型应选择Runnable JAR file

  1. 在集群上搭建Hadoop时,一切正常,为了Debug在本机搭建,使用Pseudo-Distributed Mode模式时,node的状态变为unhealthy,可以采取比较trick的方法来解决,既在yarn-site.xml中添加属性来扩大健康范围,如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
        <?xml version="1.0"?>
    <configuration>
    <property>
    <name>yarn.nodemanager.disk-health-checker.min-healthy-disks</name>
    <value>0.0</value>
    </property>
    <property>
    <name>yarn.nodemanager.disk-health-checker.max-disk-utilization-per-disk-percentage</name>
    <value>100.0</value>
    </property>
    </configuration>
阅读全文 »

UIWebView Private Method


  • UIWebView dump method:UIWebView.h
  • 设置UIWebViewWebThread线程下进行渲染,不占用主线程,代码如下:
    1
    2
    [_webView performSelector:@selector(_setDrawInWebThread:) withObject:@YES];
    [_webView performSelector:@selector(_setDrawsCheckeredPattern:) withObject:@YES];

WebResourceLoadDelegate Protocol


  • - (id)webView:(WebView *)sender identifierForInitialRequest:(NSURLRequest *)request fromDataSource:(WebDataSource *)dataSource

    该方法返回一个标识符对象,网页中的每一个资源都会调用该方法。资源包括网页中嵌入的图片、脚本、CSS、嵌入在frame中的页面。

阅读全文 »

使用PyMySQL处理大结果集的方法


最近公司项目需要向别的数据库中获取数据并同步到自己的数据库,由于是别人的库,所以没法直接使用Master-Slave同步,最终选择Python脚本来获取。

选择了PyMySQL客户端库,按照其官方教程,代码比较简单,类似如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import pymysql.cursors

# Connect to the database
connection = pymysql.connect(host='localhost',
user='user',
password='passwd',
db='db',
charset='utf8mb4',
cursorclass=pymysql.cursors.DictCursor)

try:
with connection.cursor() as cursor:
# Read a single record
sql = "SELECT `id`, `password` FROM `users`"
cursor.execute(sql)
result = cursor.fetchall()
print(result)
finally:
connection.close()

PyMySQL在获取数据时提供了fetchone()fetchall()函数来获取结果集,后来调试的时候,发现,不管是哪种方法,都会一次将所有结果获取到,这在数据量很大时将会消耗大量内存,所以有考虑是否还有别的方法,比如one-by-one的迭代获取。

在查看DictCursor游标代码时,发现了SSCursor游标类,其注释如下,意在解决数据量大的问题,正合我意。

阅读全文 »


Tips


  • iOS8.3之后,通过iTunes、iFunBox等工具已无法直接访问应用的沙盒,如果需要让自己的应用能够通过其访问,必须在应用的info.plist中添加UIFileSharingEnabled关键字,并赋值为YES,这样,就能访问其Documents目录了(注意,其它目录还是无法访问)。

  • 使用UIWebView时,发现在首次加载网页时,加载时间异常的长,其原因是服务器需要花费一定的时间来解析请求来自于哪个平台,比如PCiPhoneiPad等,以针对不同的平台响应不同的页面布局,解决该问题的方法为客户端直接请求特定版本的页面,且设置请求的UA(User Agent),如下代码:

    1
    [[NSUserDefaults standardUserDefaults] registerDefaults:@{@"UserAgent" : @"    Mozilla/5.0 (iPhone; CPU iPhone OS 10_0 like Mac OS X) AppleWebKit/602.1.38 (KHTML, like Gecko) Version/10.0 Mobile/14A300 Safari/602.1"}];
  • 在使用UIBarButtonItem,并对其使用UIImage赋值时,iOS7之后会对UIImage设置tintColor,从而改变图片的原值色,如果需要保留图片原色,可以对UIImage进行如下代码设置:

    1
    2
    UIImage *image = [UIImage imageNamed:@"myImage.png"];
    image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
阅读全文 »