unrecognized selector sent to instance in swift

之前在用 swift 来写一个项目的时候遇到了这样的一个错误:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2015-03-17 17:25:55.249 MyProject[36665:3189330] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[MyProject.Demo onRequestCompleted:]: unrecognized selector sent to instance 0x7f9fd3df1d00'
*** First throw call stack:
(
0 CoreFoundation 0x0000000102b36c65 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x0000000105097bb7 objc_exception_throw + 45
2 CoreFoundation 0x0000000102b3e0ad -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
3 CoreFoundation 0x0000000102a9413c ___forwarding___ + 988
4 CoreFoundation 0x0000000102a93cd8 _CF_forwarding_prep_0 + 120
5 CoreFoundation 0x0000000102b0654c __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12
6 CoreFoundation 0x0000000102a04a04 _CFXNotificationPost + 2484
7 Foundation 0x00000001034ec968 -[NSNotificationCenter postNotificationName:object:userInfo:] + 66
...
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)

根据以往的 Objective-C经验来看的话,这里是因为传递了错误的参数导致 selector没有被识别。而且在 call stack 中我们可以看到 :

1
-[NSNotificationCenter postNotificationName:object:userInfo:]

以此推断,是因为我们在使用 NSNotificationCenteraddObserver 方法时,传入的 selector有错误,很可能是因为我们把方法名字写错了,但是经过检查之后发现我们的代码没有错误:

1
2
3
4
5
6
NSNotificationCenter.defaultCenter().addObserver(self, selector: "onRequestCompleted:", name: MY_NOTIFICATION_REQUESTCOMPLETED, object: context)
// the onRequestCompleted: method is in swift and like this:
private func onRequestCompleted(notification: NSNotification) -> Void{
// code here
}

百思不得其解只能求助文档和 Stackoverflow 了,因为这个错误太普遍,而且在 swift 中很多人还没有去踩坑。所以花了很长的时间才发现,原来在我们的文档中有这样的一段:

To be accessible and usable in Objective-C, a Swift class must be a descendant of an Objective-C class or it must be marked @objc.

Swift declarations marked with the private modifier do not appear in the generated header. Private declarations are not exposed to Objective-C unless they are explicitly marked with @IBAction,@IBOutlet, or @objc as well.

也就是说如果我们的 Swift 方法被 Objective-C所使用,那么这个 Swift类必须是继承自 Objecitve-C类,或者必须被标记成 @objc. 而 Swift中的 private 方法不会出现在生成的头文件中,所以这些私有的方法不会暴露给 Objective-C 除非被显示的标记为 @IBAction @Iboutlet或者@objc


namespaces in swift?

Objective-C 广泛被人诟病的一点就是没有 namespace 或者 module 的概念,而如果避免冲突的话只能靠给自己的类起个独特的名字来实现。

Objective-C classes must be named uniquely not only within the code that you’re writing in a project, but also across any frameworks or bundles you might be including.

当然啦,苹果也给出了自己的建议:

In order to keep class names unique, the convention is to use prefixes on all classes. You’ll have noticed that Cocoa and Cocoa Touch class names typically start either with NS or UI. Two-letter prefixes like these are reserved by Apple for use in framework classes.
Your own classes should use three letter prefixes. These might relate to a combination of your company name and your app name, or even a specific component within your app

也就说,你需要给自己的类名起一个独特的类名前缀,最好是三个或者四个大写字母,因为两个字母的是苹果自己保留的,你起得再好,也随时都可能被剥夺,如果和你的发生冲突的话,那么只能对不起啦,后果自负吧。

当 Swift 发布之后,很多人发现依然没有类似 namespace , package 这样的关键字来定义 namespace 或者 module,但是是不是 Swift 就和 Objective-C 一样,还是要必须通过起一个独特的名字来避免命名冲突呢?Swift 的发明者 Chris Lattner 在自己的 Twitter给出了答案:

Namespacing is implicit in swift, all classes (etc) are implicitly scoped by the module (Xcode target) they are in. no class prefixes needed

也就是说在 Swift 中,没有显示的声明,而且 namespace 不是按照文件来区分的,而是按照 XCode 中 Target 的 Product Module Name 名字来隐式的加以区别,其实这更像是 module 的概念。其实举一个很简单的例子,比如在我的 App 中,我有一个 class 的名字是 UIAlertView (当然这个例子很不恰当,但是却能说明问题), 而当我想使用 UIKit 中得 UIAlertView 的时候,我可以使用:

1
2
import UIkit
let alert = UIKit.UIAlertView(frame: frame)

而我要调用自己定义的 UIAlertView 的时候,可以直接使用:

1
let myAlert = UIAlertView()

这个时候并不冲突。其实这是一个很大的进步,而且会很有用处,比如我有两个库,一个叫 FrameworkA, 一个叫 FrameworkB, 它们之间唯一的区别就是 FrameworkB 是一个 mini 版的 FrameworkA,是在 FramworkA 的基础上做了一些删减,添加了少许的新功能。但是在我们项目中要根据服务器返回的数据不同使用不同的 Framework,而这个时候我们就可以通过调用 FrameworkA.test()FrameworkB.test() 来调用不同的方法。


RTCReporting block video on iOS simulator

今天在调试程序,用 MPMoviePlayerController 去播放 video,但是程序总是 crash。设置了 All Exceptions Enabled 和 Enable Zombie Objects. 但是还是没有看到平时看到的 crash log 。调试了一个多小时也没有啥进展,正苦恼之际,无意中看到 console 上有两条不是自己 app 的 log。

1
2
Nov 20 17:32:55 rtcreporting[17045] <Info>: logging starts...
Nov 20 17:32:55 rtcreporting[17045] <Debug>: setMessageLoggingBlock: called

这个 rtcreporting 到底是个神马玩意? 外事不明问 Google, 一搜还真有相关的文章。原来这不是我的 BUG

I always encounter this issue if I’ve got an Exception Breakpoint enabled when I play a video. If I disable it then it works fine. I’ve submitted a bug report to Apple also.
This seems to be a problem with trying to play videos on the simulator.

好吧,我认了,浪费了一个多小时。不过这也怪自己,明明这么有用的线索在 console 里面,我却没有注意到。


Github 上面的一些和 swift 相关的比较有意思的资源

自从今年夏天苹果公司发布了 swift 语言之后,相关的项目就入雨后春笋一般的冒出来很多。有一些我认为很有意思的值得关注的项目在这里罗列出来。

Frameworks

Alamofire

Alamofire is an HTTP networking library written in Swift, from the creator of AFNetworking.
大神 mattt 的又一作品,和 AFNetworking 类似,但是是用纯 swift 实现的,而且只有一个文件,代码量也很少。

HanekeSwift

Haneke is a lightweight generic cache for iOS written in Swift.Haneke provides a memory and LRU disk cache for UIImage, NSData, JSON, String or any other type that can be read or written as data.Particularly, Haneke excels at working with images. It includes a zero-config image cache with automatic resizing.

Quick

Quick is a behavior-driven development framework for Swift and Objective-C. Inspired by RSpec, Specta, and Ginkgo.
一个 BDD 的测试框架,支持 Swift 和 Objective-C。

SwiftTask

Promise + progress + pause + cancel, using SwiftState (state machine).

SwiftyJSON

SwiftyJSON makes it easy to deal with JSON data in Swift.
JSON 数据解析库,使用起来非常的简单。

Dollar and Cent

Dollar is a Swift library that provides useful functional programming helper methods without extending any built in objects. It is similar to Lo-Dash or Underscore.js in Javascript.
Cent is a library that extends certain Swift object types using the extension feature and gives its two cents to Swift language.

Swifter

Tiny http server engine written in Swift programming language.
通过很少的代码,实现了一个 http server 引擎。

Design-Patterns-In-Swift

Design Patterns implemented in Swift.
由 swift 语言完成的设计模式。

ExSwift

A set of Swift extensions for standard types and classes.

Sleipnir

BDD-style framework for Swift.

Cartography

Declarative Auto Layout in Swift.
Set up your Auto Layout constraints declaratively and without any stringly typing!

Swiftz

Functional programming in Swift.
It defines purely functional data structures and functions.

下面是一些专门专门用来收集 swift 相关文章的资源

SwiftGuide

这份指南汇集了Swift语言主流学习资源,并以开发者的视角整理编排。

SwiftInFlux

An attempt to gather all that is in flux in Swift.

Awesome-swift

A collaborative list of awesome swift resources.

the-swift-programming-language-in-chinese

《The swift programming language》 的中文版本,完全由网友翻译完成。


2014 APEC 的巧妙翻译

2014 年的北京的 APEC 终于结束了,除了老百姓发明的 APEC Blue 等带有嘲讽色彩的新词之外,让我们看看网友收集的一些习大大讲话的神翻译。

山明水净夜来霜,数树深红出浅黄。这句是出自唐朝诗人刘禹锡的《秋词二首》,全诗如下:

自古逢秋悲寂寥,我言秋日胜春朝。
晴空一鹤排云上,便引诗情到碧霄。
山明水净夜来霜,数树深红出浅黄。
试上高楼清入骨,岂如春色嗾人狂。

中国的古诗讲究对仗和押韵,所以翻译起来很难。看看我们的翻译是怎么翻译的:

The water is clear and the mountain is bright. The frost comes in at night, trees are covered with deep scarlet leaves mixed with yellow that is light.
这里的 bright,nightlight也都比较押韵。

有路才能人畅其行,物畅其流

With roads in place, people and goods can flow.

志同道合

People who cherish the same ideals follow the same path.

志存高远,脚踏实地

Aspire for high and grand while planting our feet firmly on the ground.

朋友多了,路才好走

More friends, more opportunities.

大时代需要大格局,大格局需要大智慧

A great era calls for great vision, which in turn requires great wisdom.s


修改 theme 的CDN 链接到国内

本站是基于 hexo 搭建,使用了 Apollo Theme, 但是在国内访问速度超慢。

后来查了一下,原来是使用了 google 的 CDN 和调用了 google web fonts 字体库里面的字体。因为众所周知的原因,国内访问 google 的服务就是灾难(我可以骂人嘛)。

所以只能将他们改到国内的一些 CDN 服务上来,好在一些通用的代码库的 CDN 国内都有很好的支持,比如:

但是对于 google web fonts 字体库的支持,则没有那么多了,貌似目前只有360网站卫士有提供,而且使用起来非常的简单。


Using New Domain Name - Little.Cool

从今天开始启用新的域名 Little.Cool, 申请这个域名纯粹是位了好玩,现在顶级域名 .com 能申请到好的已经很不容易了,而一些像 .cool / .guru / .today 之类的还是能申请到一些让人满意的域名的。而且这些域名后缀也挺不错,方便好记。


Constants in Objective-C

定义一个全局的常量以便在 Objective-C 的项目中使用。可以通过创建一个头文件,比如 Constants.h,然后在头文件声明如下:

1
2
FOUNDATION_EXPORT NSString *const MyFirstConstant;
FOUNDATION_EXPORT NSString *const MySecondConstant;

然后在你的执行文件中 Constants.m 中:

1
2
NSString *const MyFirstConstant = @"FirstConstant";
NSString *const MySecondConstant = @"SecondConstant";

将你的 Constants.m 文件添加到你的 application/frameworktarget 中。这样你就可以使用这些全局的常量了。

注意这里使用的 FOUNDATION_EXPORT 因为,当你在 objective-c 中引入了 Foundation Framework 之后,你最好是用 FOUNDATION_EXPORT 来代替 extern, 因为在 NSObjCRuntime.h 中它包括了一些 C 和 C++ 的库,为了能更好的和这些 C 和 C++ 库兼容,所以建议用 FOUNDATION_EXPORT

http://stackoverflow.com/questions/538996/constants-in-objective-c
http://stackoverflow.com/questions/19192432/when-to-use-foundation-export?lq=1


start with sencha framework with ios

最近准备在一个简单的ios项目中使用HTML5 去开发,最终选择尝试一下 Sencha Touch。今天在这里记录一下简单的搭建步骤。

首先是安装 Sencha Touch

  • 确保自己的机器已经有了JRE环境,如果没有,安装一个.
  • 下载并且安装 Compass.

      Compass 需要你的电脑运行有 Ruby 的环境,所以你应该想安装 Ruby,至于怎么安装,这里省略100字。
      但是对于怎么安装 Compass ,可以使用下面的命令:
      - gem update --system
      - gem install compass
    
  • 然后就要安装 Sencha Cmd.

  • 下载 Sencha Touch SDK 或者 Sencha Ext JS.
  • 好了最后就是解压你下载的 SDK.
  • 这个时候你可以使用 sencha help 命令去试验一下是否安装成功。如果成功了,那祝贺你,可以进行下面的步骤了。

生成一个 iOS 的程序:

  • cd <your sencha touch directory>
  • sencha generate app <myapp> <myapp's directory>
  • cd <myapp's directory>
  • sencha app build native 因为这里我们是需要build一个ios程序,所以这里选择使用native
  • sencha app package run packager.json 这个步骤是将你build好的应用程序用本地的模拟器打开.

不过在这里我遇到了一个问题,就是使用sencha generate app命令自动生成的应用程序,在我的iphone 5的模拟器里卖弄打开的时候,上下是有黑边的。其实这是 sencha 的一个bug.不过网上也有人给出了一个临时的解决方案

其实这个也可以说是 ios 的一个bug,你如果做过native的应用程序应该知道,在我们将以前的iphone4上的程序转到iphone5上的时候是有同样的问题的,那时候我们是讲一个名字为 Default-568h@2x.png的图片放在项目目录下面,当然这个图片的大小应该是640*1136.而在这里呢我们也需要一个这样的图片,我们需要讲这个图片放在我们项目<myapp>/resources/startup下面,因为在我们build的时候,这些文件会被自动拷贝到 <myapp>/webapp/resources/startup路径下面,然后在我们的项目文件夹下的 packager.json 里添加一行 "rawConfig":"<key>UILaunchImageFile</key><string>webapp/resources/startup/Default-568h@2x.png</string>"`.

好了,Sencha之旅的第一步还算顺利吧。


WSPieChart is ok

At present, pie chart is ok.There are two classes for pie chart, one is WSPieChartView, another one is WSPieChartWithMotionView.

The difference between WSPieChartView and WSPieChartWithMotion are below:

Key points when you use WSPieChartWithMotion:

  • Carefully using the shadow. Because it will create shadow on both view and layers.Detail information you can find on the comments of class.
  • Switching data. The datas must have same titles. But they can be different order.
    The codes are just tested on simulator, not on device.