C 的快速入门指南(3)

为了能帮助编译器决定保留一个对象多长时间,你还要一个弱引用指向一个变量. 默认的,所有的变量都是强引用(==只要强引用还存在,被引用的对象就会存在下去) . 你也可以获取一个弱引用,它会随着每个强引用消失而失去它的值. 这在类成员从XCode的Builder Interface(像RC 编辑器)处获取它们的值时,会很有用,当类被销毁时,那些成员也会失去它们的值.

Strings

// Objective-C NSString* s1 = @"hello"; NSString* s2 = [NSString stringWithUTF8String:"A C String"]; sprintf(buff,"%s hello to %@","there",s2); const char* s3 = [s2 UTF8String];

NSString 是一个Objective-C字符串的不可变表示. 你可以使用其一个静态方法,或者是一个带有@前缀的字符串文本来创建NSString. 你也可以使用 %@ 来向printf家族函数来表示一个NSString,

数组

// Objective-C NSArray* a1 = [NSArray alloc] initWithObjects: @"hello",@"there",nil]; NSString* first = [a1 objectAtIndex:0];

NSArray和NSMutableArray是在Objective-C中处理数组的 两个类(两者的差异是,NSArray元素构造时必须通过构造函数,而NSMutableArray可以在之后更改)。典型构造函数的生效,你必须通过nil去作为“结尾元素”。排序/搜索/插入函数对于NSArray和NSMutableArray来说是一样的,在第一行中的例子它返回一个新的NSArray,而在NSMutableArray的例子里,它修改的是一个存在的对象。

分类

// C++ class MyString : public string { public: void printmystring() { printf("%s",c_str()); } }; // Objective-C @interface MyString (NSString) - (void) printmystring; @end @implementation MyString (NSString) - (void) printmystring { printf("%@",self); } @end // C++ MyString s1 = "hi"; s1.printmystring(); // ok string s2 = "hello"; s2.printmystring(); // error, we must change s2 from string to MyString // Objective-C NSString* s2 = @"hello"; [s2 printmystring]; // valid. We extended NSString without changing types.

C++依赖 继承机制来实现一个已知的类。这是很麻烦的,因为所有用户的实现类必须使用另外的类型名称(在例子中,MyString用来代替string)。Object-C通过使用 分类(Categories)允许扩展一个已知的类内 同型(same type 。上面链接中所有源代码在extension.h文件 (具有代表性的是像NSString+MyString.h这样的)中可以查看,上面例子中,我们立即就有可以调用新的成员函数,而不需要改变NSString类型为MyString。

块 和 Lambda

// Objective-C // member function -(void)addButtonWithTitle:(NSString*)title block:(void(^)(AlertView*, NSInteger))block; // call [object addButtonWithTitle:@"hello" block:[^(AlertView* a, NSInteger i){/*DO SOMETHING*/}];

是Objective-C 用来模拟lambda功能的一种方式. 查看Apple的文档,从AlertView的示例 (使用块的UIAlertView)可以获得更多有关块的技术.

C++ 开发者使用 Objective-C 和 ARC 的重要提示

// C++ class A { public: NSObject* s; A(); }; A :: A() { s = 0; // 可能会奔溃,这是常发生在发布模式下! }

你已经知道给所有的顾客都打两折对你而言有多痛苦了,因为你bug重重的软件会在发布模式下奔溃,而在调试模式下总是妥妥的. 没有用户会理解程序员,是不是?

让我们来看看这里发生了什么. s = 0 这一行将 0 赋值给了一个变量,而因此不管这个变量之前取值是什么,首先都会被释放掉,所以编译器在赋值之前执行了一次 [s release] . 如果 s 之前已经是 0 了,假设是在调试构建的话,不会发生任何不好的事情; 如果 s 是一个nil的话,使用[s release] 是再好也不过的. 然而,在发布模式下, s可能是一个野指针,所以它可能在被“初始化”为0之前包含任何值(这很危险是不是?).

在C++中,这并不是一个问题,因为它里面是不存在ARC的. 而在Objective-C中编译器并没有办法了解这是一次"赋值" 还是一次 "初始化" (如果是后者,它就不会发送发布消息).

下面是正确的方式:

// C++ class A { public: NSObject* s; A(); }; A :: A() :s(0) // 现在编译器就知道确定 it's 是一次初始化了, 一次就不存在 [s release] { }

现在编译器就不会去尝试调用一个 [s release] 因为它知道它是这个对象的第一次初始化. 请小心!

从Objective-C 对象到 C++ 类型的转换

// Objective-C NSObject* a = ...; void* b = (__bridge void*)a; // 你必须在Objective-C和C类型支架使用 __bridge void* c = (__bridge_retained void*)a; // 现在是一个+1的保留计数,而你必须在稍后释放这个对象 NSObject* d = (__bridge_transfer NSObject*)c; // 现在ARC取得了对象c的”拥有权“, 将其装换成一个ARC管理的NSObject.

我可以分析这一切,而我的建议是简单的. 不要 将ARC类型和非ARC类型混在一起. 如果你必须转换一些Objective-C对象的话,使用id而不是void*. 否则,你将会遇到严重的内存故障.

Objective-C 有而 C++ 没有的

分类Categories

基于NSObject的操作

YES 和 NO (等价于true和false)

NIL 和 nil (等价于0)

可命名的函数参数

self (等价于 this) 而其可以在一个构造器中被改变

C++ 有而 Objective-C 没有的

静态对象. Objective-C 中的对象不能被初始化成静态的,或者是存在于栈中. 只能是指针.

多重继承

命名空间

模板

操作符重载

STL 和算法 ;

方法可以是受保护的( protected )或者私有的( private ) (在Obj-C中,只能是公共的)

const/mutable 项

friend 方法

引用

匿名函数签名 (没有变量名称)

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/26ccc7d47b8ff8f4e77c2f9008cf25a1.html