Cocoa集合用block并发遍历的UI更新问题

现在进行集合遍历操作的时候会使用并发来提升整体执行效率, 但是在使用并发之前我们应该首先考虑当前问题是否适合使用并发.

其实只要知道了什么不适合并发就够了, 如果下一个输入严格依赖于之前的输出那么他就不适合使用并发

就昨天我遇到的问题是在操作了某UI元素之后, UI界面并没有及时更新, 在1到5秒不等的时间之中UI才完成了更新. 想了一下之后应该是因为UI只有主线程才能操作, 虽然其他线程之中也确实修改了UI元素的属性, 但是他们没有权限更新UI才造成了延迟.

只要使用dispatch_async(dispatch_get_main_queue())来切换到主线程更新UI就够了, 但是我觉得这样还不如直接使用顺序执行(只是主线程执行).

在此抛砖引玉了

Xcode 5 中的单态模式(Singleton) 在测试中失效

事情就如标题所说, 我有一个单独的类里面是Core Data的ManagedObjectContext.

然后所有需要Context的都用那个shared对象来获取context. 这里神奇的情况就出现了. 测试目标里(test target)拿到的context和主目标拿到的不一样…

更惊人的是单态对象居然初始化了两次, 这个结果无论如何都太扯淡了. 最后我是这样解决的, 因为是测试嘛, 测试里面就不去拿context了, 直接从NSManagedObject里面来获取context这样用.

– update –

可能直接在AppDelegate里面初始化的就是真的单态也说不定, 不过有待实验.

关于抓HTTP内容过程中出现的一些问题与解决方案

首先就原谅我用这种模棱两可的题目吧

1.背景

前两年听歌的时候希望能更明白歌词的意思, 就去搜歌词贴到iTunes里面, 后来感觉不是很方便, 因为要点开浏览器, 搜了, 复制了, 如何如何的. 这样就做了一个扒歌词的程序, 当时扒的是kasi-time, . 一开始一切都挺顺利的, 也挺方便. 后来是因为感觉它不是特别的全, 就去扒goo.net还是什么名的一网站来着了.

2.问题出现与解决

最开始的时候感觉这个站点很神奇, 浏览器能看到歌词, 程序就看不到了.

这无论如何都是一个很神奇的情况, 然后就用浏览器(好像用的是Safari)分析HTTP Request(啥? 你说wireshark? 用不着那个高端的东西). 然后用curl对比着一个一个header的加东西. 最后发现了他们是卡cookies和Referer的. 那么加上这两个东西就好了.

用了没几天又完蛋了, 这次更神奇, 用浏览器都不能复制了. 他那个不能复制可不是

onselectstart="return false;"

这种. 它是用了HTML5的Canvas, 把歌词画了出来.

我(好像?)也是这时候知道了Canvas这神奇东西

不过这个反而更好处理, Canvas是客户端绘制的, 那么你必须提供绘制内容(这里就是歌词), 直接去把歌词那出来就好了. 问题也就解决了.

3. 最近遇到的情况

我时不时的会做一些方便自己的东西, 扒漫画, 过滤RSS, 扒歌词什么的. 也见过各种神奇的所谓’防盗’手段. 同时, 本着不给别人添麻烦与尊重他人劳动的想法, 我也不会大范围公布那些东西. 当然拿出来也不一定有人用哈.

今天, 我又想着扒个小说弄成epub看来着(造epub这个事儿有空再说). 发现我的工具不好使了, 然后打开出错的页面一看就傻了, HTML里面赫然写着

能看到这页面的除了寄生虫和小偷也只有傻逼了吧…

顿时让我有很复杂的感觉…同时比较惊讶, 我一个月也扒不了10次(我没那么多闲工夫去看小说, 其实大部分小说下载了也不看), 至于这样防么? 而且我本身程序有伪装的…  后来看了下里面的内容发现不是说我, 指名道姓的说某公司和某程序还什么的是寄生虫什么的.

嘛, 要说我也算是小偷吧, 寄生虫的话我本身也没有利益牵扯其中应该就不算了. 细想的话我也没对任何人造成损失, 只是自己看而已, 也没有把方法工具到处说. 扯远了, 不好意思

4. 此次事件的感想

其实我很理解那个站点的人感想, 自己辛辛苦苦弄出来的东西, 却给他人做了嫁衣. 但是我不能赞同这种做法, 虽然可能在HTML里面写注释一般用户可能看不到, 但是写的这么明白合适么? 不会造成更强的对抗心理么? 这样会对自己造成更大的损失不是么?

如果是我的话, 我肯定不会写那些东西. 就算要写也会用个URIEncode或者Base64之类的, 这样的话一般用户就真的看不到了. 同时封堵对方的话还是得想别的办法, 骂人什么的一点儿用处也没有不是么? 具体方法我就不在这里说了.

5. 结语

最后说下读任何HTTP内容出现问题的处理方法. 下面的方案可以一级一级的试, 用CURL就挺好.

  1. 把Cookies带上
  2. 把Referer带上
  3. 检查正常访问的HTTP Request与错误的内容不一致的地方
  4. 再不行就得分析HTTP协议了

可能有人说如果人家跳转过怎么办(就那个HTTP 302还是几来着的东西), 这个不是问题, 因为我们只需要最后一步正确就好了, 我不认为会有哪个神经病去把WEB容器重新实现一下来做引用记录什么的. 因为收入支出比太不平衡了, 做这东西如果用了1周的话, 骗过他也许连一天都用不了.

用HTML5-canvas实现像iTunes11那样的专辑配色方案

这是本科毕业设计里的Demo部分, 拿出来分享一下.

1. 缘起
去年(2012年)12月的时候更新了iTunes11, 然后发现了新的album界面, 专辑封面和各曲目信息的面板完全融合了起来, 当时出了震惊, 再没别的想法了. 图1是效果演示
iTunesDemo图1

2. 功能分析
兴奋之余, 作为一个程序员自然会思考它是如何实现的, 网上搜了一圈也没找到(2012年底那会儿), 然后就想着自己试着做做吧.
分析了一下以后我是这样认为的(仅仅是认为, 不是说人家就是那么做的). 首先通过图片(专辑封面)的左边缘以及上边缘的颜色拿出背景色, 然后再分析整个图片颜色拿出几个与背景色对比强烈的前景色.
最后的图片应该是用分析出来的背景色加上alpha通道又覆盖了一下, 然后边缘也使用背景色逐渐的加大Alpha通道覆盖, 产生了类似渐变的融合效果. 因为我本身没学过图形图像处理, 所以可能有更好更正规的方法, 如果各位知道的话, 还望赐教.

有了初步的想法就可以动手了, 我当时是用Haskell解析PNG的. 最后做出来是个控制台程序(CLI)不容易看效果, 于是这个HTML5版本的就出现了. 其实, HTML5的这个Demo反而功能更强大(擦汗…), 很多东西浏览器都给你做了. 在此感谢Webkit, 感谢Apple, 感谢Google.

3. 实现工具的基础知识
先普及下HTML5的Canvas.简单地说, 这是用来在HTML页面里面绘制图形的一个容器, 就是通过这个能”画画”的容器完成了我们的演示.

var image = new Image();
image.src = 'URL of the image';
var canvas = document.getElementById("testCanvas");
// 假设我们的canvas, ID是textCanvas
var ctx = canvas.getContext("2d");
var w = canvas.attributes.width.value;
var h = canvas.attributes.height.value;
ctx.drawImage(0,0,w,h,image); // 在Canvas上画图
// 各个参数分别是起点坐标x, 起点坐标y, 宽度w, 高度h, 被画的图像image
var imgdata = ctx.getImageData(0, 0, w, h); // 这里是关键
// getImageData就可以取出所有的像素, 通过这个我们就可以分析颜色了.
var pixels = imgdata.data;
// 因为取出来的是一个"对象", data属性就是RGBA的颜色矩阵了,

至此, 我们的准备工作就完成了.

4. 具体实现过程
第2部分已经说的挺清楚了, 这部分就不过多赘述.
getImageData拿出颜色矩阵分析就好了, 但是因为24位RGB色的组合太多了, 2563=1677216, 如果每个颜色分别计算的话, 不仅计算量大, 内存估计也受不了. 所以这里要降低精度. 一开始单纯的把24-bits转成8-bits了(就那个8位色323), 效果十分扯淡, 和背景融合的时候一看就不是一个颜色. 后来想了想是不是能算两个颜色的距离呢? 因为真的是不知道怎么做, 搜了下也没太搜到, 就用了欧几里得距离. 把RGB映射到3维空间中算两点间距离.
这也有这的问题, 设想有点A与r, 那么有球体以点A为中心, r为半径, 所有球面上的点P都与A的距离为R. 极端的说就是有个灰色, 黑色(偏0)与白色(偏255)和它的距离是一样的, 这就比较麻烦了. 好在RGB都是[0,255]区间内的整数. 最后的解决方案是距离弄成2, 然后对两个点A, B取算数平均值, 这样尽可能地降低精度损失.
如果两个像素距离不大于2就当做同一个点对待(之后要取算术平均值), 减少了不同颜色的数量, 处理过所有的像素之后从大到小进行排序, 得到列表[E0(P0, C0), E1(P1, C1), ..., En(Pn, Cn)]. 以出现次数最多的E0的次数C0为基点, 与E1, E2, E3计算欧式距离, 如果小于规定阀值F, 就计算E0, 与Ex像素Px加权平均值作为背景色.
这部分可能说的不够清楚, 还望见谅

前景色和上面的类型差不多, 不过阀值要大很多, 因为不需要与图片融合起来, 所以还进行了降低精度处理, 具体是对每个颜色都右移了4位再左移4位(要保证还是[0,255]), 只是这次的排序依据是与背景色的距离.

 5. 后记
Demo主要用的是CoffeeScript, 这东西好像挺火的, 也说的挺好, 什么加入了Python, Ruby, Haskell的语法糖啥的, 但是我感觉意外的不好用, 曾几度准备用JavaScript重写的, 不过考虑到”没正经用就说不好”这个行为还是坚持下来了.

最后的demo看起图片与背景不是那么”融合”, 那个是alpha混合的问题, 去掉了步骤2说的背景色全部覆盖就看起来真的融合起来了.本文示例代码下载

根据不同文件使用不同的vim配置

这两天拿django做东西玩, python用的缩进是4 space, html是2 space(from:http://google-styleguide.googlecode.com/), 结果就出问题了, 原来一直是用全局的indent设置的(在$HOME/.vimrc里面)

就去搜了一下怎么办, 一搜就出来了, vim太牛了

我写在了这里

$HOME/.vim/bundle/django/syntax/html.vim

里面写

setlocal shiftwidth=2
setlocal tabstop=2

大功告成, 这样HTML的缩进是2 space了

python3解决zip的乱码问题

有时候下载回来的zip文件解压以后文件名是乱码的, windows用户用apploc来模拟其他的语言环境可以解决这个问题, 但是我等*nix用户咋办呢? 自己写程序吧.

首先要知道zip的内部编码是

IBM437

, 不管你的系统编码是什么, 反正都是用IBM437存在zip文件里的. 所以如果A编码的系统压缩了的zip, A编码的系统去解压缩是正常的, 但是其他编码的系统解压就是乱码了.

具体地说我在中文windows系统下压的zip去, 日文windows或者不管什么文的OSX上解压一定是乱码.

既然知道了过程原理那就能动手了. 这里我用python3做的

from zipfile import ZipFile

InnerEncoding='IBM437'  # inner encoding
UsingEncoding='GB18030' # assume the file from a windows

if __name__ == '__main__':
  zf = ZipFile('file.zip')
  nl = zf.namelist() # get files name in zip file
  # Here we'll get first file name 
  print(filename.encode(InnerEncoding).decode(UsingEncoding))

这样应该就正常了, 完整程序太长, 就不贴了

p.s. ZipFile是python写的, 所以如果文件经过加密的话速度奇慢, 我是取得文件名以后用unzip解压然后再改名的

Terminal的中文支持

先说方案:

添加下面的东西到~/.inputrc里面

set input-meta on
set output-meta on
set convert-meta off

到这里中文输入应该是没问题了, 但是有些软件是读取locale信息的, NAS上受限制的状态也装不了locale所以, 就自己写吧, 添加

export LC_ALL='en_US.UTF-8'

到.profile里, 我是写到~/.bash_profile里面了, 用zsh的写进zshrc里面就行

来源

——– 缘起 ——-

前两天折腾NAS, 完蛋了好几次, 最后还是换回官方固件了…

说到底非得装debian就是因为很多软件不支持Unicode, unrar, python3什么的, 总让你写ascii怎么说也说不过去呀. unrar还好, 最不能忍的就是python3一写中文就出

UnicodeEncodeError: 'ascii' codec can't encode character '\u9644' in position 0: ordinal not in range(128)

嘛, 最后还是没用debian………