calabash-ios failed with “No frameworks Group found. Aborting.”

I have quick looked many BDD tools and calabash looks right. It is a quite straightforward solution: integrate a http server into iOS project and bridge actions of cucumber step and iOS runtime using accessibility facility. Because predefined steps are quite complete, it is possible just write feature specs in  Gherkin without touching ruby code.

But it is always so struggling to ramp up a new open source technology.  The first try just failed, even with simplest environment, with a brand new simple view project.

Error message explains itself, I need create this Frameworks group in project to let script continue running. Or it just aborted, no target duplicated, no integration.

The interesting part is, it is an issue known for over 1 year: https://github.com/calabash/calabash-ios/issues/533

XcodeGhost, 墙, 全民编程, 以及未来

这些天 XcodeGhost 闹得沸沸扬扬. 作为一个好歹写程序的年头比 Twitter 或者 Weibo 上大多数人长的老程序员来说, XcodeGhost 本身其实并没什么高深之处, 也没有什么出乎意料的巨大危害. 甚至, 把它称为病毒也是错误的, 最多不过是个 malware 而已. 并且, 相对于国内 Windows desktop 以及 Android 系统里的 malware 们而言, XcodeGhost 太小儿科了. 好歹 iOS 的 sandbox 还控制着权限, Windows 全家桶们可是早就把你的底裤都翻光了. 没见着有这么激动嘛.

我赞同云风的观点, 这个玩意跟你 link 了一个谁谁谁的什么分析跟踪, 广告展示, 乃至于流行的支付, 分享等等的 SDK 进去没有任何差别. 技术一点说, 两者都是把一些代码加入到了你的应用中, 并且在某些时候会得到执行.  弹窗骗用户帐号密码? 都可以. 发送一些用户信息到远端服务器上? 都可以. 安装企业证书签名的 App? 都可以. 顺便说一下, 国内对企业证书的滥用才是比 XcodeGhost 更大得多危险得多的安全漏洞.

究其原因不能不说到墙. 然而不是说把责任都推到墙上就完事了的. 需要想一想为什么这样, 以及这又反映了什么.

首先, XcodeGhost 这个东西也是只有在国内这个环境里才会造成这么大范围的传播和扩散. Yes, 墙功不可没. 不过试想一下, 假设现在把墙撤了, 我认为 XcodeGhost 还是会同样大量迅速扩散的. 对于多年来习惯于四处下载盗版音乐电影软件的毫无职业素养和基本常识的你国众多小白程序员和产品经理来说, 对, 像 adoal 说的, 连免费软件都要盗版的人来说, 扔到迅雷上去或者从百度云盘拉, 必然会是比从 Mac App Store 或者 Apple developer site 下载安装更优先的选择. 再往深了想原因就是多种互相纠缠在一起了, 恕不赘述. 想探讨的请我吃饭咱们边吃边聊好了. 哈.

然后回过来说墙. 经过从计算机萌芽期开始长期不懈的盗版洗礼, 以及 10 年左右的强有力的寡妇网封锁. 你国小白们, 不光是普通用户, 连程序员都是, 已经不知不觉地形成了相当完整的墙内思维了. 搜索上百度, 软件下盗版, iOS 用 XX 助手, Malware 遍地的 android 商店们就更不用说了. 大家的整个计算机生存环境已经是与你国以外用户完全不同的一个环境了. 很好, 非常好. 我觉得可以说, 大中华局域网已经基本完成了. 别说我危言耸听, 看看: 与世界隔离, 需要的所有东西都可以在内网设法找到无论什么途径来源如何, 这不是局域网是什么? 说件更悲哀的事, 跟十几岁的孩子们聊天, 已经几乎没有人知道 Google 是什么了. 这不能怪他们, 一个不能访问的网站, 自然就相当于不存在. 物理封锁其实还不算什么, 思维被封锁了, 才是真正的被封锁. 就如今的情形看, 我持悲观态度.

这个问题就到此吧, 我比较不喜欢煽情, 无论是热烈吹捧还是血泪控诉. 有脑子的人自己会去体会. 别老替别人哭和笑.

然后是全民编程. 这个话题这几年热得发烫. 然而对照 XcodeGhost 干了什么, 再想一想. 至少我觉得在目前, 全民编程这个想法很傻冒, 跟天真, 十分类似于别有用心的人提出来的. 连目前算是专业的程序员们都缺乏基本的编码常识, 你让见到随便哪个提示框就乖乖地把自己的帐号密码输进去的“民”来编程? 别说我阴谋论, 至少我是绝对不敢用这种民编出来的程的.

说到这里就是 IoT 了, 全民编程是在这个背景下提出来的. 我相信未来是人机结合体的时代, 但是安全是最大的问题. 从这个意义上讲, 未来还是有漫长的路要走, 因为, 信任这一安全上至关重要的点, 至今还是很难保证的. 是的, 我信任从 Mac App Store 安装的 Xcode, 但是我无法确认别人也是从 Mac App Store 安装的而不是从迅雷或者百度下载的带有 XcodeGhost 的. 所以, 这还是个难题, 除非所有代码都是我自己写的, 问题是, 我写得过来吗?

The struggling with CocoaPods seems got ending

CocoaPods is really cool tool to incorporate 3rd party open source library,  it is even cooler with the app built-in framework support added in recent (since 0.36) and  dedup-ing of targets along with simpler name in 0.38.

Naturally, I’m considering to use CocoaPods as a primary tool to organize the project, which means private repo and destruct the project into pods.

At beginning, I made my mind up like:

屏幕快照 2015-09-19 下午1.14.32

But soon I got a lot issue to struggle with, thus the working environment is involuted to:

CocoaPods repo setup with struggling env

Yep, I had to draw this to clear my mind.

One of those modules  come with CoreData model (.xcdatamodeld) and the model just didn’t appear after pod install. And lately I get it, the bundle folder itself is better to be added as a source file, but I still need to add it back to project, or it will not be compiled. And, I can’t.

After quite a lot struggling, I believe the answer can only dig out from its source code. CocoaPod is written in Ruby, which I haven’t learn yet, which means I have to learn Ruby firstly, which is why I didn’t read its code at first time.

Fortunately, Ruby is a simple language, it took about half day to learn the syntax. Thanks a lot to a good tutorial (http://ruby-doc.com/docs/ProgrammingRuby/) and a great quick reference (http://www.zenspider.com/Languages/Ruby/QuickRef.html). Here is my study notes:

Ruby Language

— Oh, no, I should have read (http://edwinmeyer.com/Release_Integrated_RHG_09_10_2008/) at first moment, it is way far efficient written for me.

Reading source code of CocoaPods is a little confusing, I cannot find the entry point until reading its CLAide sub project. Other parts are quite readable, soon I located the file_accessor using Dir glob to list files survived cleaning, which doesn’t understand specific folder is a bundle and will list its contents, those contents obviously are not recognized as source file. Considering I haven’t read all the source code and it is quite possible to have side effects to patch glob-ing part, I decided to insert the patch in adding source reference part.

So that a quick and a little dirty patch is created and PR is submitted. If you happen having same idea by now, try my fork (https://github.com/pinxue/CocoaPods).  After cloned, you may install it by:

gem build ./cocopods.gemspec
sudo gem install --local ./cocoapods-0.39.0.beta.4.gem

BTW, CocoaPods includes 1645 spec requirements (unit tests) and 1650 integration test requirements, really surprised me.

 

 

Update ordered ToMany relationship in CoreData

It is a well known bug, when a relationship is checked with ordered, some Dynamically-Generated accessor Methods (add*) will throw exception, some others (insert*) are just not generated.

I ran into this issue again. Yeah, I met it about 1 year ago. I’m one hundred percent sure it is a bug. And a patch is created by someone long ago https://github.com/CFKevinRef/KCOrderedAccessorFix

But, it seems Apple guys had decided not to fix it. The radar item are closed now!

Fortunately,  -mutableOrderedSetValueForKey: method mentioned by document always works. I guess it is the time for Apple to update their document (https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreData/Articles/cdUsingMOs.html#//apple_ref/doc/uid/TP40001803-SW3) :

Typically, however, you do not want to set an entire relationship, instead you want to add or remove a single element at a time. To do this, you should usemutableSetValueForKey: or one of the automatically-generated relationship mutator methods (see Dynamically-Generated Accessor Methods): unless it is order!

Yet another trap of CocoaPods

Creating a pod in my private repo, it worked fine till I made some uncertain changes. Now running ‘pod install’ in Example will complain:

Resolving dependencies of `Podfile`
[!] Unable to satisfy the following requirements:

– `DataModel (from `../`)` required by `Podfile`
– `DataModel (from `../`)` required by `Podfile`
– `DataModel (= 0.1.0)` required by `Podfile.lock`

And eventually, I figured it out, it is caused by iOS platform version which I just modified to reflect truth of framework in bundle requires 8.0.

  s.platform     = :ios, ‘8.0’

It works like a charm when the version is 7.0 or 7.1 . How could it be so weird?! Well, it is not weird indeed, I just didn’t give the iOS version in Podspec file. It will work with right iOS platform version, like:

platform :ios, ‘8.0’

The error information didn’t mention platform version, it should have saved my day!

Xcode7 的两个小坑

Xcode7 还在 beta,时不时崩一下什么的倒也是预料之中的事,没料到的是之前用着好好的,今天升完 El Capitan 之后,模拟器居然不见了,设备倒是在 schema 栏右边里能看到,不过注明不能用。

看了看系统日志是 Simulator 服务不停的崩。查了查,有人已经分析过了:
http://stackoverflow.com/questions/31551480/xcode-7-beta-4-ios-simulators-missing-and-not-installable
简单点说,去把7.x / 8.x 的 simulator 映像文件都移走或者干脆删除,就好了。

另外,beta4 会报怨 CoreData 模型文件没有指定版本号,这新建的文件哪来的版本好,在 Editor 里给建了一个版本终于不 warning 了。

Little tricks with XCTest

Tried to call all other tests in one test function.

    // alternate what setup done
    // full tests in alternated state
    NSArray * tests = [FileLibraryTests testInvocations];
    for (NSInvocation * inv in tests ) {
        NSString * sel = NSStringFromSelector(inv.selector);
        if (![sel containsString:@"WithInit"] && ![sel containsString:@"Monitoring"]) {
            [inv invokeWithTarget:self];
        }
    }
    //back to normal state

And just noticed XCode6 added XCTestExpetation, no longer need semaphore like:

    #import 
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
dispatch_after(dispatch_time(0, (int64_t)(0.2 * NSEC_PER_SEC)), 
        dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), 
        ^{
            ... dispatch_semaphore_signal(sema); ...
        }
    );
dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, 30*NSEC_PER_SEC));

It is much simple to test async operations now:

    XCTestExpectation *expectation = [self expectationWithDescription:@"xxx"];
// invoke it in code async executing
    ... ^(){
        [expectation fulfill];
    } ...
[self waitForExpectationsWithTimeout:1 handler:^(NSError *error) {
        // cleanup.
    }];