独立开发者的自白:Objective-C最糟糕的13件事
2015-12-22 14:48
826 查看
本文的作者是一名具有多年开发经验的独立游戏开发者,他从一个专业开发者视角深入剖析Objective-C,将其与其他编程语言相比,解读Objective-C的优与缺,并总结出Objective-C的13件最为糟糕的事。
本文的作者Anton Zherdev是一名具有多年开发经验的独立游戏开发者,他从一个专业开发者的视角深入剖析Objective-C,将其与C、Java等其他语言相比,解读Objective-C的优与缺,以最为精炼的话语总结出他所认为的Objective-C的13件最为糟糕的事,直指Objective-C的不足之处,与列位开发者分享。以下为文章全文:
1. 笨重的语法
在Objective-C中,必须要编写大量的代码来声明一个类或属性。对比下面的Objective-C和Scala的代码段,效果不言而喻。
[js]
view plaincopyprint?
@interface Foo : NSObject
@property (readonly) int bar;
- (instancetype)initWithBar:(int)bar;
+ (instancetype)fooWithBar:(int)bar;
@end
@implementation Foo
- (instancetype)initWithBar:(int)bar {
self = [super init];
if (self) {
_bar = bar;
}
return self;
}
+ (instancetype)fooWithBar:(int)bar {
return [[self alloc] initWithBar:bar];
}
@end
[js]
view plaincopyprint?
class Foo {
private int bar;
public Foo(int bar) {
this.bar = bar;
}
public int getBar() {
return bar;
}
}
[js]
view plaincopyprint?
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。
[b][js]
view plaincopyprint?
@interface Foo : NSObject
- (void)foo;
@end
@implementation Foo
- (void)foo{}
@end
@interface Bar : NSObject
- (void)bar;
@end
@implementation Bar
- (void)bar {
[(id)self foo]; //OK
[(id)self bar]; //OK, but runtime error
[(id)self qux]; //Compiler error
Foo* foo = self; //OK
}
@end
5. 不支持泛型
在Objective-C中,要想查看容器类所属是不可能的,而且,编译器也不能进行检查。这方面,Java显然要好得多。
[js]
view plaincopyprint?
NSArray* array = [foo array];
id item = [array objectAtIndex:0]; //item is anything
[js]
view plaincopyprint?
List<A> array = foo.getArray();
A item = array.get(0);
6. 核心库集匮乏
在Objective-C的核心库中,缺少诸如分类设置、字典(地图)、链表、队列等实用集。没有它们,在进行红黑树分类和字典等开发管理时会花费大量的时间。
还有一个问题就是缺乏几项非常不错的功能,尤其是函数式编程能力有所缺失,尽管如此,但在Objective中,也有非常不错的一项功能,就是开发者可以使用分类简单地扩展核心集。
7. 缺少枚举
尽管Objective-C包含有C的枚举,但却仅仅只是一组变量,开发者必须要编写代码来实现一些类似于Java的枚举,比如链接属性等。
[js]
view plaincopyprint?
enum Foo {
Foo1(1),
Foo2(2),
Foo2(3);
final int bar;
Foo(int bar) {
this.bar = bar;
}
}
8. 可怕的block语法
block是Objective-C一项非常强大的功能,但我却不知如何声明带有block类型的变量或函数参数。看下面这段代码便可知晓。
[js]
view plaincopyprint?
//Declare variable foo
void (^foo)(id obj, NSUInteger idx, BOOL *stop);
9. 操作符重载缺失
如果说无需操作符重载的话,难免有些欠妥,因为定义向量数学运算符是件很正常的事情,它使代码更具有可读性。
[js]
view plaincopyprint?
[[[a add:b] sub:[c mul:f]] div:f];
(a + b - c*f)/f;
10. 匿名类不足
定义一个协议或接口并不像想象中那么简单,要想轻而易举地实现,就必须要先实现一个完整的类。
[js]
view plaincopyprint?
@protocol I
- (void)f;
@end
@interface Foo : NSObject
- (void)foo;
- (void)qux;
@end
@implementation Foo
- (void)foo {
id<I> i = [[Baz alloc] initWithFoo:self];
}
@end
@interface Baz : NSObject<I>
- (instancetype)initWithFoo:(Foo*)foo;
@end
@implementation B {
Foo* _foo;
}
- (instancetype)initWithFoo:(Foo*)foo {
self = [super init];
if(self) {
_foo = foo;
}
return self;
}
- (void)f {
[_foo bar];
}
@end
[js]
view plaincopyprint?
interface I {
void f();
}
class Foo {
void foo() {
I i = new I() {
void f() {
bar();
}
};
}
void bar() {
}
}
11. 糟糕的构造函数
使用构造函数创建新对象很常见,但在Objective-C中,要想创建对象,还需调用两个函数。当然,开发者可以编写方法直接避免该问题的发生。
[js]
view plaincopyprint?
@interface Foo : NSObject
- (instancetype)initWithBar:(int)bar;
+ (instancetype)newWithBar:(int)bar;
@end
@implementation Foo {
int* _bar;
}
- (instancetype)initWithBar:(int)bar {
self = [super init];
if(self) {
_bar = bar;
}
return self;
}
+ (instancetype)newWithBar:(int)bar {
return [[self alloc] initWithI:bar];
}
@end
12. 不透明的数值包装器
在Objective-C中,要想在集合或其他容器中使用数值是件很费劲的事情,除了原有代码之外,还需添加一个NSNumber类。
[js]
view plaincopyprint?
int a = 1;
int b = 2;
int c = a + b;
NSNumber* aWrap = @(a);
NSNumber* bWrap = @(b);
NSNumber* cWrap = @([aWrap intValue] + [bWrap intValue]);
13. 缺乏包管理系统
在Objective-C中,开发者必须要使用到前缀,以避免类名重合。此外,还要在头文件中对所需类进行声明,以防头文件冲突,编译失败。
本文的作者Anton Zherdev是一名具有多年开发经验的独立游戏开发者,他从一个专业开发者的视角深入剖析Objective-C,将其与C、Java等其他语言相比,解读Objective-C的优与缺,以最为精炼的话语总结出他所认为的Objective-C的13件最为糟糕的事,直指Objective-C的不足之处,与列位开发者分享。以下为文章全文:
1. 笨重的语法
在Objective-C中,必须要编写大量的代码来声明一个类或属性。对比下面的Objective-C和Scala的代码段,效果不言而喻。
[js]
view plaincopyprint?
@interface Foo : NSObject
@property (readonly) int bar;
- (instancetype)initWithBar:(int)bar;
+ (instancetype)fooWithBar:(int)bar;
@end
@implementation Foo
- (instancetype)initWithBar:(int)bar {
self = [super init];
if (self) {
_bar = bar;
}
return self;
}
+ (instancetype)fooWithBar:(int)bar {
return [[self alloc] initWithBar:bar];
}
@end
@interface Foo : NSObject @property (readonly) int bar; - (instancetype)initWithBar:(int)bar; + (instancetype)fooWithBar:(int)bar; @end @implementation Foo - (instancetype)initWithBar:(int)bar { self = [super init]; if (self) { _bar = bar; } return self; } + (instancetype)fooWithBar:(int)bar { return [[self alloc] initWithBar:bar]; } @end
[js]
view plaincopyprint?
class Foo {
private int bar;
public Foo(int bar) {
this.bar = bar;
}
public int getBar() {
return bar;
}
}
class Foo { private int bar; public Foo(int bar) { this.bar = bar; } public int getBar() { return bar; } }
[js]
view plaincopyprint?
class Foo(bar : Int)
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。
[b][js]
view plaincopyprint?
@interface Foo : NSObject
- (void)foo;
@end
@implementation Foo
- (void)foo{}
@end
@interface Bar : NSObject
- (void)bar;
@end
@implementation Bar
- (void)bar {
[(id)self foo]; //OK
[(id)self bar]; //OK, but runtime error
[(id)self qux]; //Compiler error
Foo* foo = self; //OK
}
@end
@interface Foo : NSObject - (void)foo; @end @implementation Foo - (void)foo{} @end @interface Bar : NSObject - (void)bar; @end @implementation Bar - (void)bar { [(id)self foo]; //OK [(id)self bar]; //OK, but runtime error [(id)self qux]; //Compiler error Foo* foo = self; //OK } @end
5. 不支持泛型
在Objective-C中,要想查看容器类所属是不可能的,而且,编译器也不能进行检查。这方面,Java显然要好得多。
[js]
view plaincopyprint?
NSArray* array = [foo array];
id item = [array objectAtIndex:0]; //item is anything
NSArray* array = [foo array]; id item = [array objectAtIndex:0]; //item is anything
[js]
view plaincopyprint?
List<A> array = foo.getArray();
A item = array.get(0);
List<A> array = foo.getArray(); A item = array.get(0);
6. 核心库集匮乏
在Objective-C的核心库中,缺少诸如分类设置、字典(地图)、链表、队列等实用集。没有它们,在进行红黑树分类和字典等开发管理时会花费大量的时间。
还有一个问题就是缺乏几项非常不错的功能,尤其是函数式编程能力有所缺失,尽管如此,但在Objective中,也有非常不错的一项功能,就是开发者可以使用分类简单地扩展核心集。
7. 缺少枚举
尽管Objective-C包含有C的枚举,但却仅仅只是一组变量,开发者必须要编写代码来实现一些类似于Java的枚举,比如链接属性等。
[js]
view plaincopyprint?
enum Foo {
Foo1(1),
Foo2(2),
Foo2(3);
final int bar;
Foo(int bar) {
this.bar = bar;
}
}
enum Foo { Foo1(1), Foo2(2), Foo2(3); final int bar; Foo(int bar) { this.bar = bar; } }
8. 可怕的block语法
block是Objective-C一项非常强大的功能,但我却不知如何声明带有block类型的变量或函数参数。看下面这段代码便可知晓。
[js]
view plaincopyprint?
//Declare variable foo
void (^foo)(id obj, NSUInteger idx, BOOL *stop);
//Declare variable foo void (^foo)(id obj, NSUInteger idx, BOOL *stop);
9. 操作符重载缺失
如果说无需操作符重载的话,难免有些欠妥,因为定义向量数学运算符是件很正常的事情,它使代码更具有可读性。
[js]
view plaincopyprint?
[[[a add:b] sub:[c mul:f]] div:f];
(a + b - c*f)/f;
[[[a add:b] sub:[c mul:f]] div:f]; (a + b - c*f)/f;
10. 匿名类不足
定义一个协议或接口并不像想象中那么简单,要想轻而易举地实现,就必须要先实现一个完整的类。
[js]
view plaincopyprint?
@protocol I
- (void)f;
@end
@interface Foo : NSObject
- (void)foo;
- (void)qux;
@end
@implementation Foo
- (void)foo {
id<I> i = [[Baz alloc] initWithFoo:self];
}
@end
@interface Baz : NSObject<I>
- (instancetype)initWithFoo:(Foo*)foo;
@end
@implementation B {
Foo* _foo;
}
- (instancetype)initWithFoo:(Foo*)foo {
self = [super init];
if(self) {
_foo = foo;
}
return self;
}
- (void)f {
[_foo bar];
}
@end
@protocol I - (void)f; @end @interface Foo : NSObject - (void)foo; - (void)qux; @end @implementation Foo - (void)foo { id<I> i = [[Baz alloc] initWithFoo:self]; } @end @interface Baz : NSObject<I> - (instancetype)initWithFoo:(Foo*)foo; @end @implementation B { Foo* _foo; } - (instancetype)initWithFoo:(Foo*)foo { self = [super init]; if(self) { _foo = foo; } return self; } - (void)f { [_foo bar]; } @end
[js]
view plaincopyprint?
interface I {
void f();
}
class Foo {
void foo() {
I i = new I() {
void f() {
bar();
}
};
}
void bar() {
}
}
interface I { void f(); } class Foo { void foo() { I i = new I() { void f() { bar(); } }; } void bar() { } }
11. 糟糕的构造函数
使用构造函数创建新对象很常见,但在Objective-C中,要想创建对象,还需调用两个函数。当然,开发者可以编写方法直接避免该问题的发生。
[js]
view plaincopyprint?
@interface Foo : NSObject
- (instancetype)initWithBar:(int)bar;
+ (instancetype)newWithBar:(int)bar;
@end
@implementation Foo {
int* _bar;
}
- (instancetype)initWithBar:(int)bar {
self = [super init];
if(self) {
_bar = bar;
}
return self;
}
+ (instancetype)newWithBar:(int)bar {
return [[self alloc] initWithI:bar];
}
@end
@interface Foo : NSObject - (instancetype)initWithBar:(int)bar; + (instancetype)newWithBar:(int)bar; @end @implementation Foo { int* _bar; } - (instancetype)initWithBar:(int)bar { self = [super init]; if(self) { _bar = bar; } return self; } + (instancetype)newWithBar:(int)bar { return [[self alloc] initWithI:bar]; } @end
12. 不透明的数值包装器
在Objective-C中,要想在集合或其他容器中使用数值是件很费劲的事情,除了原有代码之外,还需添加一个NSNumber类。
[js]
view plaincopyprint?
int a = 1;
int b = 2;
int c = a + b;
NSNumber* aWrap = @(a);
NSNumber* bWrap = @(b);
NSNumber* cWrap = @([aWrap intValue] + [bWrap intValue]);
int a = 1; int b = 2; int c = a + b; NSNumber* aWrap = @(a); NSNumber* bWrap = @(b); NSNumber* cWrap = @([aWrap intValue] + [bWrap intValue]);
13. 缺乏包管理系统
在Objective-C中,开发者必须要使用到前缀,以避免类名重合。此外,还要在头文件中对所需类进行声明,以防头文件冲突,编译失败。
相关文章推荐
- Objective-c语言_委托模式
- Objective-C对象之类对象和元类对象
- Objective-c语言_单例模式
- Objective-C_语言_协议
- Objective-C_语言_延展
- Objective-C_语言_类目
- 【jQuery】使用$.extend()扩展Object对象
- OC学习篇之---Foundation框架中的NSObject对象
- Objective C设计模式之外观模式facade
- opencv人脸检测--cvHaarDetectObjects函数
- 【iOS】swift-ObjectC 在iOS 8中使用UIAlertController
- html系列教程--nav noscript option optgroup object
- DTO、Model,ViewModel,Object,Entity作用
- Objective-C和Swift中初始化方法比较
- Objective-C:笔记:语句和表达式
- ObObjective-C:笔记:Block 代码块
- ObObjective-C:笔记:3
- ObObjective-C:笔记:6
- ObObjective-C:笔记:7
- ObObjective-C:笔记:8