独立开发者的自白:Objective-C最糟糕的13件事

本文的作者Anton Zherdev是一名具有多年开发经验的独立游戏开发者,他从一个专业开发者的视角深入剖析Objective-C,将其与C、Java等其他语言相比,解读Objective-C的优与缺,以最为精炼的话语总结出他所认为的Objective-C的13件最为糟糕的事,直指Objective-C的不足之处,与列位开发者分享。以下为文章全文:

1. 笨重的语法

在Objective-C中,必须要编写大量的代码来声明一个类或属性。对比下面的Objective-C和Scala的代码段,效果不言而喻。

[js]  view plain copy
  1. @interface Foo : NSObject  
  2. @property (readonly) int bar;  
  3. - (instancetype)initWithBar:(int)bar;  
  4. + (instancetype)fooWithBar:(int)bar;  
  5. @end  
  6. @implementation Foo  
  7. - (instancetype)initWithBar:(int)bar {  
  8.    self = [super init];  
  9.    if (self) {  
  10.        _bar = bar;  
  11.    }  
  12.    return self;  
  13. }  
  14. + (instancetype)fooWithBar:(int)bar {  
  15.    return [[self alloc] initWithBar:bar];  
  16. }  
  17. @end  

[js]  view plain copy
  1. class Foo {  
  2.    private int bar;  
  3.    public Foo(int bar) {  
  4.         this.bar = bar;  
  5.    }  
  6.    public int getBar() {  
  7.         return bar;  
  8.    }  
  9. }  
[js]  view plain copy
  1. class Foo(bar : Int)  

2. 方括号

前缀括号是一件非常虐心的事情,尽管Objective-C有IDE自动解决这一问题,却也大大降低了代码的可读性。

3. 内存管理

与具有垃圾回收器的编程语言相比,Objective-C的内存更容易泄漏。虽然垃圾回收器可能会导致程序不定时回收,但也可通过设置来避免。在Objective-C中,尽管已经有ARC来解决这一问题,并且,开发者可以很好地利用它来解决一些弱引用的问题,却还存在着无法解析引用周期的状况。

举个例子,如果你在block中使用self,并将其发送给另一个存储该block的类,便会导致内存泄漏,而且还很难发现。并且,如果想要在类字段中保存block,就必须要将其copy过来,否则,当block被调用时,程序也就崩溃了。

4. 动态且不安全的类型系统

Objective-C有一个非常奇怪的类型系统。任何消息,只要在视图中可声明,就可以将其发送给id类对象,但却无法回避id。

[js]  view plain copy
  1. @interface Foo : NSObject  
  2. - (void)foo;  
  3. @end  
  4. @implementation Foo  
  5. - (void)foo{}  
  6. @end  
  7.    
  8. @interface Bar : NSObject  
  9. - (void)bar;  
  10. @end  
  11. @implementation Bar  
  12. - (void)bar {  
  13.   [(id)self foo]; //OK  
  14.   [(id)self bar]; //OK, but runtime error  
  15.   [(id)self qux]; //Compiler error  
  16.   Foo* foo = self; //OK  
  17. }  
  18. @end  

5. 不支持泛型

在Objective-C中,要想查看容器类所属是不可能的,而且,编译器也不能进行检查。这方面,Java显然要好得多。

[js]  view plain copy
  1. NSArray* array = [foo array];  
  2. id item = [array objectAtIndex:0]; //item is anything  

6. 核心库集匮乏

在Objective-C的核心库中,缺少诸如分类设置、字典(地图)、链表、队列等实用集。没有它们,在进行红黑树分类和字典等开发管理时会花费大量的时间。

还有一个问题就是缺乏几项非常不错的功能,尤其是函数式编程能力有所缺失,尽管如此,但在Objective中,也有非常不错的一项功能,就是开发者可以使用分类简单地扩展核心集。

7. 缺少枚举

尽管Objective-C包含有C的枚举,但却仅仅只是一组变量,开发者必须要编写代码来实现一些类似于Java的枚举,比如链接属性等。

[js]  view plain copy
  1. enum Foo {  
  2.     Foo1(1),  
  3.     Foo2(2),  
  4.     Foo2(3);  
  5.     final int bar;  
  6.     Foo(int bar) {  
  7.         this.bar = bar;  
  8.     }  
  9. }  

8. 可怕的block语法

block是Objective-C一项非常强大的功能,但我却不知如何声明带有block类型的变量或函数参数。看下面这段代码便可知晓。

[js]  view plain copy
  1. //Declare variable foo  
  2. void (^foo)(id obj, NSUInteger idx, BOOL *stop);  

9. 操作符重载缺失

如果说无需操作符重载的话,难免有些欠妥,因为定义向量数学运算符是件很正常的事情,它使代码更具有可读性。

[js]  view plain copy
  1. [[[a add:b] sub:[c mul:f]] div:f];  
  2. (a + b - c*f)/f;  

10. 匿名类不足

定义一个协议或接口并不像想象中那么简单,要想轻而易举地实现,就必须要先实现一个完整的类。

[js]  view plain copy
  1. @protocol I  
  2. - (void)f;  
  3. @end  
  4.    
  5. @interface Foo : NSObject  
  6. - (void)foo;  
  7. - (void)qux;  
  8. @end  
  9. @implementation Foo  
  10. - (void)foo {  
  11.    id i = [[Baz alloc] initWithFoo:self];  
  12. }  
  13. @end  
  14.    
  15. @interface Baz : NSObject  
  16. - (instancetype)initWithFoo:(Foo*)foo;  
  17. @end  
  18. @implementation B {  
  19.     Foo* _foo;  
  20. }  
  21.    
  22. - (instancetype)initWithFoo:(Foo*)foo {  
  23.    self = [super init];  
  24.    if(self) {  
  25.    _foo = foo;  
  26. }  
  27.    return self;  
  28. }  
  29.    
  30. - (void)f {  
  31.    [_foo bar];  
  32. }  
  33. @end  
[js]  view plain copy
  1. interface I {  
  2.    void f();  
  3. }  
  4.    
  5. class Foo {  
  6.    void foo() {  
  7.        I i = new I() {  
  8.          void f() {  
  9.              bar();  
  10.          }  
  11.      };  
  12.   }  
  13.   void bar() {  
  14.   }  
  15. }  

11. 糟糕的构造函数

使用构造函数创建新对象很常见,但在Objective-C中,要想创建对象,还需调用两个函数。当然,开发者可以编写方法直接避免该问题的发生。

[js]  view plain copy
  1. @interface Foo : NSObject  
  2. - (instancetype)initWithBar:(int)bar;  
  3. + (instancetype)newWithBar:(int)bar;  
  4. @end  
  5. @implementation Foo {  
  6.      int* _bar;  
  7. }  
  8. - (instancetype)initWithBar:(int)bar {  
  9.    self = [super init];  
  10.    if(self) {  
  11.    _bar = bar;  
  12.   }  
  13.   return self;  
  14. }  
  15. + (instancetype)newWithBar:(int)bar {  
  16.    return [[self alloc] initWithI:bar];  
  17. }  
  18. @end  

12. 不透明的数值包装器

在Objective-C中,要想在集合或其他容器中使用数值是件很费劲的事情,除了原有代码之外,还需添加一个NSNumber类

[js]  view plain copy
  1. int a = 1;  
  2. int b = 2;  
  3. int c = a + b;  
  4. NSNumber* aWrap = @(a);  
  5. NSNumber* bWrap = @(b);  
  6. NSNumber* cWrap = @([aWrap intValue] + [bWrap intValue]);  

13. 缺乏包管理系统

在Objective-C中,开发者必须要使用到前缀,以避免类名重合。此外,还要在头文件中对所需类进行声明,以防头文件冲突,编译失败。

你可能感兴趣的:(iOS开发)