Objective-C代码学习大纲(3)

Objective-C代码学习大纲(3)

2011-05-11 14:06 佚名 otierney  字号:T | T
一键收藏,随时查看,分享好友!

本文为台湾出版的《Objective-C学习大纲》的翻译文档,系统介绍了Objective-C代码,很多名词为台湾同胞特指词汇,在学习时仔细研读才能体会。

AD:干货来了,不要等!WOT2015 北京站演讲PPT开放下载!

 

详细说明...

多重参数

目前为止我还没展示如何传递多个参数。这个语法乍看之下不是很直觉,不过它却是来自一个十分受欢迎的 Smalltalk 版本。

 

  1. Fraction.h 
  2.  
  3. ... 
  4.  
  5. -(void) setNumerator: (int) n andDenominator: (int) d; 
  6.  
  7. ... 
  8.  
  9. Fraction.m 
  10.  
  11. ... 
  12.  
  13. -(void) setNumerator: (int) n andDenominator: (int) d { 
  14.  
  15. nnumerator = n; 
  16.  
  17. ddenominator = d; 
  18.  
  19.  
  20. ... 
  21.  
  22. main.m 
  23.  
  24. #import 
  25.  
  26. #import "Fraction.h" 
  27.  
  28. int main( int argc, const char *argv[] ) { 
  29.  
  30. // create a new instance 
  31.  
  32. Fraction *frac = [[Fraction alloc] init]; 
  33.  
  34. Fraction *frac2 = [[Fraction alloc] init]; 
  35.  
  36. // set the values 
  37.  
  38. [frac setNumerator: 1]; 
  39.  
  40. [frac setDenominator: 3]; 
  41.  
  42. // combined set 
  43.  
  44. [frac2 setNumerator: 1 andDenominator: 5]; 
  45.  
  46. // print it 
  47.  
  48. printf( "The fraction is: " ); 
  49.  
  50. [frac print]; 
  51.  
  52. printf( "\n" ); 
  53.  
  54. // print it 
  55.  
  56. printf( "Fraction 2 is: " ); 
  57.  
  58. [frac2 print]; 
  59.  
  60. printf( "\n" ); 
  61.  
  62. // free memory 
  63.  
  64. [frac release]; 
  65.  
  66. [frac2 release]; 
  67.  
  68. return 0; 
  69.  

 

output

  1. The fraction is: 1/3 
  2.  
  3. Fraction 2 is: 1/5 

这个 method 实际上叫做 setNumerator:andDenominator:

加入其他参数的方法就跟加入第二个时一样,即 method:label1:label2:label3: ,而唿叫的方法是 [obj method: param1 label1: param2 label2: param3 label3: param4]

Labels 是非必要的,所以可以有一个像这样的 method:method:::,简单的省略 label 名称,但以 : 区隔参数。并不建议这样使用。

建构子(Constructors)

 

  1. Fraction.h 
  2.  
  3. ... 
  4.  
  5. -(Fraction*) initWithNumerator: (int) n denominator: (int) d; 
  6.  
  7. ... 
  8.  
  9. Fraction.m 
  10.  
  11. ... 
  12.  
  13. -(Fraction*) initWithNumerator: (int) n denominator: (int) d { 
  14.  
  15. self = [super init]; 
  16.  
  17. if ( self ) { 
  18.  
  19. [self setNumerator: n andDenominator: d]; 
  20.  
  21.  
  22. return self; 
  23.  
  24.  
  25. ... 
  26.  
  27. main.m 
  28.  
  29. #import 
  30.  
  31. #import "Fraction.h" 
  32.  
  33. int main( int argc, const char *argv[] ) { 
  34.  
  35. // create a new instance 
  36.  
  37. Fraction *frac = [[Fraction alloc] init]; 
  38.  
  39. Fraction *frac2 = [[Fraction alloc] init]; 
  40.  
  41. Fraction *frac3 = [[Fraction alloc] initWithNumerator: 3 denominator: 10]; 
  42.  
  43. // set the values 
  44.  
  45. [frac setNumerator: 1]; 
  46.  
  47. [frac setDenominator: 3]; 
  48.  
  49. // combined set 
  50.  
  51. [frac2 setNumerator: 1 andDenominator: 5]; 
  52.  
  53. // print it 
  54.  
  55. printf( "The fraction is: " ); 
  56.  
  57. [frac print]; 
  58.  
  59. printf( "\n" ); 
  60.  
  61. printf( "Fraction 2 is: " ); 
  62.  
  63. [frac2 print]; 
  64.  
  65. printf( "\n" ); 
  66.  
  67. printf( "Fraction 3 is: " ); 
  68.  
  69. [frac3 print]; 
  70.  
  71. printf( "\n" ); 
  72.  
  73. // free memory 
  74.  
  75. [frac release]; 
  76.  
  77. [frac2 release]; 
  78.  
  79. [frac3 release]; 
  80.  
  81. return 0; 
  82.  

 

output

  1. The fraction is: 1/3 
  2.  
  3. Fraction 2 is: 1/5 
  4.  
  5. Fraction 3 is: 3/10 

@interface 裡的宣告就如同正常的函式。

@implementation 使用了一个新的关键字:super

如同 Java,Objective-C 只有一个 parent class(父类别)。

使用 [super init] 来存取 Super constructor,这个动作需要适当的继承设计。

你将这个动作回传的 instance 指派给另一新个关键字:self。Self 很像 C++ 与 Java 的 this 指标。

if ( self ) 跟 ( self != nil ) 一样,是为了确定 super constructor 成功传回了一个新物件。nil 是 Objective-C 用来表达 C/C++ 中 NULL 的方式,可以引入 NSObject 来取得。

当你初始化变数以后,你用传回 self 的方式来传回自己的位址。

预设的建构子是 -(id) init。

技术上来说,Objective-C 中的建构子就是一个 "init" method,而不像 C++ 与 Java 有特殊的结构。

存取权限

预设的权限是 @protected

Java 实作的方式是在 methods 与变数前面加上 public/private/protected 修饰语,而 Objective-C 的作法则更像 C++ 对于 instance variable(译注:C++ 术语一般称为 data members)的方式。

  1. Access.h 
  2.  
  3. #import 
  4.  
  5. @interface Access: NSObject { 
  6.  
  7. @public 
  8.  
  9. int publicVar; 
  10.  
  11. @private 
  12.  
  13. int privateVar; 
  14.  
  15. int privateVar2; 
  16.  
  17. @protected 
  18.  
  19. int protectedVar; 
  20.  
  21.  
  22. @end 
  23.  
  24. Access.m 
  25.  
  26. #import "Access.h" 
  27.  
  28. @implementation Access 
  29.  
  30. @end 
  31.  
  32. main.m 
  33.  
  34. #import "Access.h" 
  35.  
  36. #import 
  37.  
  38. int main( int argc, const char *argv[] ) { 
  39.  
  40. Access *a = [[Access alloc] init]; 
  41.  
  42. // works 
  43.  
  44. a->publicVar = 5; 
  45.  
  46. printf( "public var: %i\n", a->publicVar ); 
  47.  
  48. // doesn't compile 
  49.  
  50. //a->privateVar = 10; 
  51.  
  52. //printf( "private var: %i\n", a->privateVar ); 
  53.  
  54. [a release]; 
  55.  
  56. return 0; 
  57.  

output

  1. public var: 5 

如同你所看到的,就像 C++ 中 private: [list of vars] public: [list of vars] 的格式,它只是改成了@private, @protected, 等等。

Class level access

 

  1. ClassA.h 
  2.  
  3. #import 
  4.  
  5. static int count; 
  6.  
  7. @interface ClassA: NSObject 
  8.  
  9. +(int) initCount; 
  10.  
  11. +(void) initialize; 
  12.  
  13. @end 
  14.  
  15. ClassA.m 
  16.  
  17. #import "ClassA.h" 
  18.  
  19. @implementation ClassA 
  20.  
  21. -(id) init { 
  22.  
  23. self = [super init]; 
  24.  
  25. count++; 
  26.  
  27. return self; 
  28.  
  29.  
  30. +(int) initCount { 
  31.  
  32. return count; 
  33.  
  34.  
  35. +(void) initialize { 
  36.  
  37. count = 0; 
  38.  
  39.  
  40. @end 
  41.  
  42. main.m 
  43.  
  44. #import "ClassA.h" 
  45.  
  46. #import 
  47.  
  48. int main( int argc, const char *argv[] ) { 
  49.  
  50. ClassA *c1 = [[ClassA alloc] init]; 
  51.  
  52. ClassA *c2 = [[ClassA alloc] init]; 
  53.  
  54. // print count 
  55.  
  56. printf( "ClassA count: %i\n", [ClassA initCount] ); 
  57.  
  58. ClassA *c3 = [[ClassA alloc] init]; 
  59.  
  60. // print count again 
  61.  
  62. printf( "ClassA count: %i\n", [ClassA initCount] ); 
  63.  
  64. [c1 release]; 
  65.  
  66. [c2 release]; 
  67.  
  68. [c3 release]; 
  69.  
  70. return 0; 
  71.  

 

output

  1. ClassA count: 2 
  2.  
  3. ClassA count: 3 

static int count = 0; 这是 class variable 宣告的方式。其实这种变数摆在这裡并不理想,比较好的解法是像 Java 实作 static class variables 的方法。然而,它确实能用。

+(int) initCount; 这是回传 count 值的实际 method。请注意这细微的差别!这裡在 type 前面不用减号 - 而改用加号 +。加号 + 表示这是一个 class level function。(译注:许多文件中,class level functions 被称为 class functions 或 class method)

存取这个变数跟存取一般成员变数没有两样,就像 ClassA 中的 count++ 用法。

+(void) initialize method is 在 Objective-C 开始执行你的程式时被唿叫,而且它也被每个 class 唿叫。这是初始化像我们的 count 这类 class level variables 的好地方。

异常情况(Exceptions)

注意:异常处理只有 Mac OS X 10.3 以上才支援。

 

  1. CupWarningException.h 
  2.  
  3. #import 
  4.  
  5. @interface CupWarningException: NSException 
  6.  
  7. @end 
  8.  
  9. CupWarningException.m 
  10.  
  11. #import "CupWarningException.h" 
  12.  
  13. @implementation CupWarningException 
  14.  
  15. @end 
  16.  
  17. CupOverflowException.h 
  18.  
  19. #import 
  20.  
  21. @interface CupOverflowException: NSException 
  22.  
  23. @end 
  24.  
  25. CupOverflowException.m 
  26.  
  27. #import "CupOverflowException.h" 
  28.  
  29. @implementation CupOverflowException 
  30.  
  31. @end 
  32.  
  33. Cup.h 
  34.  
  35. #import 
  36.  
  37. @interface Cup: NSObject { 
  38.  
  39. int level; 
  40.  
  41.  
  42. -(int) level; 
  43.  
  44. -(void) setLevel: (int) l; 
  45.  
  46. -(void) fill; 
  47.  
  48. -(void) empty; 
  49.  
  50. -(void) print; 
  51.  
  52. @end 
  53.  
  54. Cup.m 
  55.  
  56. #import "Cup.h" 
  57.  
  58. #import "CupOverflowException.h" 
  59.  
  60. #import "CupWarningException.h" 
  61.  
  62. #import 
  63.  
  64. #import 
  65.  
  66. @implementation Cup 
  67.  
  68. -(id) init { 
  69.  
  70. self = [super init]; 
  71.  
  72. if ( self ) { 
  73.  
  74. [self setLevel: 0]; 
  75.  
  76.  
  77. return self; 
  78.  
  79.  
  80. -(int) level { 
  81.  
  82. return level; 
  83.  
  84.  
  85. -(void) setLevel: (int) l { 
  86.  
  87. llevel = l; 
  88.  
  89. if ( level > 100 ) { 
  90.  
  91. // throw overflow 
  92.  
  93. NSException *e = [CupOverflowException 
  94.  
  95. exceptionWithName: @"CupOverflowException" 
  96.  
  97. reason: @"The level is above 100" 
  98.  
  99. userInfo: nil]; 
  100.  
  101. @throw e; 
  102.  
  103. } else if ( level >= 50 ) { 
  104.  
  105. // throw warning 
  106.  
  107. NSException *e = [CupWarningException 
  108.  
  109. exceptionWithName: @"CupWarningException" 
  110.  
  111. reason: @"The level is above or at 50" 
  112.  
  113. userInfo: nil]; 
  114.  
  115. @throw e; 
  116.  
  117. } else if ( level 0 ) { 
  118.  
  119. // throw exception 
  120.  
  121. NSException *e = [NSException 
  122.  
  123. exceptionWithName: @"CupUnderflowException" 
  124.  
  125. reason: @"The level is below 0" 
  126.  
  127. userInfo: nil]; 
  128.  
  129. @throw e; 
  130.  
  131.  
  132.  
  133. -(void) fill { 
  134.  
  135. [self setLevel: level + 10]; 
  136.  
  137.  
  138. -(void) empty { 
  139.  
  140. [self setLevel: level - 10]; 
  141.  
  142.  
  143. -(void) print { 
  144.  
  145. printf( "Cup level is: %i\n", level ); 
  146.  
  147.  
  148. @end 
  149.  
  150. main.m 
  151.  
  152. #import "Cup.h" 
  153.  
  154. #import "CupOverflowException.h" 
  155.  
  156. #import "CupWarningException.h" 
  157.  
  158. #import 
  159.  
  160. #import 
  161.  
  162. #import 
  163.  
  164. #import 
  165.  
  166. int main( int argc, const char *argv[] ) { 
  167.  
  168. NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
  169.  
  170. Cup *cup = [[Cup alloc] init]; 
  171.  
  172. int i; 
  173.  
  174. // this will work 
  175.  
  176. for ( i = 0; i 4; i++ ) { 
  177.  
  178. [cup fill]; 
  179.  
  180. [cup print]; 
  181.  
  182.  
  183. // this will throw exceptions 
  184.  
  185. for ( i = 0; i 7; i++ ) { 
  186.  
  187. @try { 
  188.  
  189. [cup fill]; 
  190.  
  191. } @catch ( CupWarningException *e ) { 
  192.  
  193. printf( "%s: ", [[e name] cString] ); 
  194.  
  195. } @catch ( CupOverflowException *e ) { 
  196.  
  197. printf( "%s: ", [[e name] cString] ); 
  198.  
  199. } @finally { 
  200.  
  201. [cup print]; 
  202.  
  203.  
  204.  
  205. // throw a generic exception 
  206.  
  207. @try { 
  208.  
  209. [cup setLevel: -1]; 
  210.  
  211. } @catch ( NSException *e ) { 
  212.  
  213. printf( "%s: %s\n", [[e name] cString], [[e reason] cString] ); 
  214.  
  215.  
  216. // free memory 
  217.  
  218. [cup release]; 
  219.  
  220. [pool release]; 
  221.  

 

output

  1. Cup level is: 10 
  2.  
  3. Cup level is: 20 
  4.  
  5. Cup level is: 30 
  6.  
  7. Cup level is: 40 
  8.  
  9. CupWarningException: Cup level is: 50 
  10.  
  11. CupWarningException: Cup level is: 60 
  12.  
  13. CupWarningException: Cup level is: 70 
  14.  
  15. CupWarningException: Cup level is: 80 
  16.  
  17. CupWarningException: Cup level is: 90 
  18.  
  19. CupWarningException: Cup level is: 100 
  20.  
  21. CupOverflowException: Cup level is: 110 
  22.  
  23. CupUnderflowException: The level is below 0 

NSAutoreleasePool 是一个记忆体管理类别。现在先别管它是干嘛的。

Exceptions(异常情况)的丢出不需要扩充(extend)NSException 物件,你可简单的用 id 来代表它: @catch ( id e ) { ... }

还有一个 finally 区块,它的行为就像 Java 的异常处理方式,finally 区块的内容保证会被唿叫。

Cup.m 裡的 @"CupOverflowException" 是一个 NSString 常数物件。在 Objective-C 中,@ 符号通常用来代表这是语言的衍生部分。C 语言形式的字串(C string)就像 C/C++ 一样是 "String constant" 的形式,型别为 char *。

你可能感兴趣的:(Objective-C)