编程

Objective-C 无法识别静态库中的Category方法

最近正在写一些库,并且用上篇文章的方式实现了一个头文件对应多个实现文件的一个类。

但是在测试自己的库的时候,发现了这样一个问题:

我有一个类,叫MyClass,并且头文件MyClass.h中声明了基础的一些方法,并且声明一些Category方法,其中包含方法

- (void)getSomeData;

并且该方法在MyClass+Extension.m中实现(其他基础的方法在MyClass.m中实现)。

但是,在测试过程中使用该库,并调用

[MyClass getSomeData]

程序崩溃了,查看崩溃的原因是:unrecognized selector [MyClass getSomeData]
可是编译的时候一点警告都没有。从Objective-C的语法上来讲,这样子完全是没有错的。那么到底是什么原因导致崩溃的呢?
后来在搜索到苹果的这个网页后,才知道要使用静态库中,同一个头文件对应多个实现文件的静态库时,编译时需要加上链接-ObjC才可以正常执行。
加上ObjC后,编译的时候,编译器会将库中所有涉及到某个类的内容全部加载进来,这样会导致生成体积会变大,不过这是理所当然的,因为链入的代码变多了。

所以,最好在分Category去实现的时候,对应的Category还是要有对应的头文件,将不同的Category拆成不同的头文件,只引用有用的头文件,例如把上篇文章的头文件拆成MyClass.h和MyClass+Extension.h,分别对应MyClass.m和MyClass+Extension.m。这样子使用的时候我只要引用MyClass.h和MyClass+Extension.h就可以了,即可以保持Category的好处,又不用引入ObjC使链接器将我不想用的MyClass+ExtensionAnother之类的也链进来导致编译体积变大了。

(1) 条评论

Objective-C 如何让一个头文件对应多个实现文件

Objective-C中,没办法像C/C++一样,一个头文件简单的对应多个文件,链接的时候我们什么都不用管。一般来说Objective-C是一个头文件的对应一个实现文件,他的所有实现都是在@implement和@end之间的。

但是Objective-C有个动态扩展一个已经存在的类的方法,Category。假设已经存在实现好的类 MyClass,你只要实现自己的Category,例如:

  1. @interface MyClass(Extension)
  2.  
  3. - (void)aaa;
  4.  
  5. @end

再实现对应的

  1. @implement MyClass(Extension)
  2.  
  3. - (void)aaa
  4. {
  5. //do your things
  6. }
  7.  
  8. @end

这样 你就给已经存在的MyClass类增加了一个叫aaa的方法。

我们可以利用这个特性来实现单头文件对应多实现文件。
阅读这篇文章的剩余部分 »

没有评论

Knotes便签

之前一直想找一个便签,Tomboy不是我要的那种,我是希望可以像Mac地下的stickies一样,就像我们平时的便签纸一样,到处贴的那种。

今天找了一下,发现Knotes的效果正好是我想要的,比Mac下的Stickies让我更满意,呵呵,平时经常忘了一些东西,就喜欢把他贴到桌面去,这样看看桌面是不是就记起来了。

show一下我的乱七八糟的东西

screenshot

感觉还是不错的。

(4) 条评论

kernel/time.c中的mktime算法(下)

好,现在我们已经得到一个公式来计算mon月之前已经过去的日子了:
X=year/4-year/100+year/400+(year-1)*365+30*mon-30+(mon+mon/7)/2+day-1
现在我们来计算一下公元1年1月1日:
经过下面这段代码的转换之后,year=0,mon=11,day=1.。

  1. if (0 >= (int) (mon -= 2)) {
  2.         mon += 12;    /* Puts Feb last since it has leap day */
  3.         year -= 1;
  4. }

代入表达式:0-0+0+(0-1)*365 + 30 *11 -30 + (11+11/7)/2 + 1-1=365-306=-59.
这个59显而易见的是由我们将1,2月置后造成的,所以这个公式需要加上一个修正值:59.
再减去1970年离公元1年的日子719162,那么我们的mktime就完成了。
改正后的公式为:
X=year/4-year/100+year/400+(year-1)*365+30*mon-30+(mon+mon/7)/2+day-1 + 59 - 719162
让我们对这个公式进行整理吧,整理后得到:
X=year/4-year/100+year/400+year*365 + 214*mon/7 + day - 719499
和linux源码中的mktime公式并不一样!!不是原来的367*mon/12!

为什么会有这样的区别呢?让我们来回忆一样推导g(mon)的第三步:
g(mon)=30*mon -30 + (mon + mon/7)/2;
事实上,大家会发现,在这儿,这个表达式并不是唯一的!下面这个表达式也是正确的:
g(mon)=30*mon -30 + (mon + mon/6)/2;
让我们用新的g(mon)代入最后的式子,你会惊喜的发现得到的是下面的式子:
year/4-year/100+year/400+year*365 + 367*mon/12 + day - 719499
正是kernel/time.c中的mktime表达式!
阅读这篇文章的剩余部分 »

(14) 条评论

kernel/time.c中的mktime算法(上)

去年在acstar的限时比赛时写过一个程序,是计算某日到2000年1月1日的天数,当时我写的算法用了大概50行,使用的算法很烂。今天在linux内核源码中看到mktime的时候,很清楚折服于它如此简单的算法(据说是Gauss算法),同时犯糊涂。

我将源码摘抄如下:
kernel/time.c

  1. /* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
  2. * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
  3. * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
  4. *
  5. * [For the Julian calendar (which was used in Russia before 1917,
  6. * Britain & colonies before 1752, anywhere else before 1582,
  7. * and is still in use by some communities) leave out the
  8. * -year/100+year/400 terms, and add 10.]
  9. *
  10. * This algorithm was first published by Gauss (I think).
  11. *
  12. * WARNING: this function will overflow on 2106-02-07 06:28:16 on
  13. * machines were long is 32-bit! (However, as time_t is signed, we
  14. * will already get problems at other places on 2038-01-19 03:14:08)
  15. */
  16. unsigned long
  17. mktime(const unsigned int year0, const unsigned int mon0,
  18.        const unsigned int day, const unsigned int hour,
  19.        const unsigned int min, const unsigned int sec)
  20. {
  21.     unsigned int mon = mon0, year = year0;
  22.  
  23.     /* 1..12 -> 11,12,1..10 */
  24.     if (0 >= (int) (mon -= 2)) {
  25.         mon += 12;    /* Puts Feb last since it has leap day */
  26.         year -= 1;
  27.     }
  28.  
  29.     return ((((unsigned long)
  30.           (year/4 - year/100 + year/400 + 367*mon/12 + day) +
  31.           year*365 - 719499
  32.         )*24 + hour /* now have hours */
  33.       )*60 + min /* now have minutes */
  34.     )*60 + sec; /* finally seconds */
  35. }

阅读这篇文章的剩余部分 »

没有评论

« 下一页