Objective-C 编程/入门
在 Objective C 中,文件通常使用扩展名 .h
用于接口文件,使用扩展名 .m
用于实现文件。
这些 Objective C 文件是文本文件,包含关于如何编写程序的指令。例如,这是一个最小的“Hello World”程序
#import <stdio.h>
int main (void)
{
printf ("Hello world!\n");
}
#import
是一个预处理器指令,它将导致编译器导入文件 stdio.h 的内容,就像它在文件中一样。C 程序员可能会立即看到此指令的一个细微差异,即 C 使用 #include
指令代替。Objective-C 程序员通常使用 #import
指令,它包含指定的头文件,但与 #include
不同,#import
只执行一次。
Objective-C 最常用于开发 Apple 产品 Mac OS X 和 iOS(iPodTouch、iPhone、iPad-Mini 和 iPad)的软件。它也用于 Linux 上的 GNUStep 环境。如果您在 Mac 上开发,可以使用 Apple 的不错的图形用户界面 (GUI) XCode,它是免费的。
有文档,但不要期望 Python 教程。例如,有一个关于 iOS 编程的教程,其中一半是关于如何使用 IDE,一半是关于创建一个简单的手机应用程序,该应用程序从输入字段读取数据,并在按下按钮时在标签中输出消息。
iOS 教程的基本步骤是
- 从主菜单栏创建一个项目,选择项目类型“单视图和控制器”。
- 确保项目页面左上角的项目摘要显示正在编译到手机模拟器,如果正在设计的 UI 是在手机上。
- 打开您正在使用的设备(手机)的主故事板文件,并使用拖放来设计表单。
- 使用左上角的按钮切换到辅助编辑器,并将故事板放在一个窗格中,并将生成的视图控制器的接口文件的源视图放在另一个窗格中。
- 通过按住 Control 键并将鼠标从用户界面设计页面拖动到接口文件的源代码,在故事板对象(字段、按钮)和接口文件之间建立图形连接。
- 将图形元素控制拖动到视图控制器的接口文件时,会出现提示显示选择。简单的常见情况是将它们设置为“出口”,这些出口提供了对用户界面设计器中可读或可写的图形元素的引用;对于按钮元素,创建一个操作连接并填写方法名称。按钮的操作通常是代码需要开始的地方。
- 还有一个名为委托的概念,在本例中,委托用于在文本字段输入小部件 (UITextField) 的键盘输入中按下回车键时放弃焦点。委托只是一个处理程序,可以实现协议中定义的一组方法签名中的一个或多个方法,在本例中,是
UITextFieldDelegate
协议。按下回车键时调用的委托方法不是“returnButtonPressed”,而是“textFieldShouldReturn”,这将在协议文档中找到。在textFieldShouldReturn
内部,应该调用文本字段的“resignFirstResponder”方法以允许键盘隐藏,作为对按下回车键的响应。 - 该教程使用几个不必要但说明性的步骤来实现操作按钮的操作,即将输入文本复制到标签。例如,将文本字段的文本
NSString
属性复制到视图控制器的NSString
属性,该属性是作为练习创建的;然后使用alloc
和initWithFormat
创建一个局部范围的NSString
变量,以便将文本字段中输入的名称与欢迎消息连接起来。然后将局部NSString
变量分配给标签的文本属性,该属性具有省略的alloc-initCopy
语义。更短但等效的是“self.label.text = [[NSString alloc] initWithFormat:@"Hello %s!", self.textField.text]
;”。
在此之后,可以尝试更复杂的学习示例,例如
- 创建一个计算器,其中公式在文本字段中输入,公式被解析,结果在标签中返回。
- 这可以通过创建一个解析器-词法分析器类来完成,该类负责对给定字符串进行自顶向下的解析,并进行一次字符前瞻。解析器具有递归语法,方法可以表示语法中的非终结符,词法分析器方法用于将字符的终结字符串转换为数字。如果有效计算的初始符号是“L”,那么 L -> E
是语法的初始行,由对方法 E
的调用表示(例如 [ self E ];
)。表达式由一个或多个用 + 或 - 分隔的项组成,并且可以递归地表示为
E -> T | T + E | T - E
因此 E
可以是以下三种情况之一,T
,或者如果 T
后的符号是 +
,则为 T + E
,或者如果 T
后的符号是 -
,则为 T - E
。E
方法的开始可能是:-
-(void) E {
[self T];
char ch = [self lookahead];
if ( ch == '+' ) {
[self nextchar];
[self E];
[self plus];
} else if ( ch == '-') {
[self next char];
[self E];
[self minus];
}
}
'plus'
和 'minus'
在最后被调用的原因是,正常的算术语法可以转换为逆波兰表示法,其中操作数可以被加载到堆栈中,操作对推送到堆栈的最后两个操作数进行操作,并且替代实现可以是将给定的输入字符串从正常表示法转换为逆波兰表示法,然后遍历该表示法以按顺序进行推入/弹出/操作。否则,在本实现中,'plus'
可能看起来像
// stack is a NSMutableArray* initialised in -(id)init
-(void) plus {
NSDecimalNumber* n2 = [stack lastObject];
[stack deleteLastObject];
NSDecimalNumber* n1 = [stack lastObject];
[stack deleteLastObject];
NSDecimalNumber *res = [[NSDecimalNumber alloc] initWithDouble: ( [n1 doubleValue] + [n2 doubleValue] ) ];
[stack addObject:res];
}
plus
的另一种实现是,有一个存储 NSString
令牌的第二个可变数组实例,并且 'plus'
只将 '+'
NSString
令牌推送到这个第二个数组中。解析完成后,遍历该数组,并使用第三个可变数组按顺序处理每个令牌,推入数字令牌,并为操作弹出数字,然后推入结果。
第三种实现可以消除堆栈的使用,方法是让操作返回数字,这些数字是应用操作或转换数字词素的结果。这依赖于程序堆栈不仅使用递归来提供语法规则的排序,还进行深度优先处理,以便中间结果存储在调用者的程序堆栈帧中的堆栈中。例如,如果函数 expr
返回 [self term] + [self term]
,则第一次调用 term
的返回值在第二个调用 term
之前被保存在寄存器中并被推送到 CPU 堆栈中。
语法的其余部分类似于
- 项是一个因子,因子乘以项,或因子除以项,并且
- 因子是一个带括号的表达式或一个实体,并且
- 当前唯一的实体是一个常数。
常数是对词素的解析,词素由(忽略空格)初始 + 或 -、数字字符串和/或小数点组成,小数点出现一次。练习是写出语法,然后设计语法的其他方法,以及常数词法分析器。
- 如果
T -> F | F * T | F / T
,则除法不能按预期工作,因为*
或/
后的T
将递归执行,直到T -> F
,然后操作从最后一个F
向后计算,因此3/3/3 = .333
将是3/(3/3) = 3
,这不是正确的。解决方法是重新实现语法以消除右侧计算。T
始终是F
后跟* T
、/ T
或什么都不做,这可以称为T'
或Tdash
,因此T -> F T'
,并且T' -> * F T'
|/ F T'
|e
。想法是通过用第三个符号T'
包裹第一个F
之后的可选项递归部分,将终止解析的F
移动到左侧,T'
始终可选地是'e'
或空的解析。这种技术也有助于解决语法中的一些歧义,例如 if-then-statement-(optional)-else-statement -或- if-then-statement-(optional)-else... - 如果表达式语法规则没有以类似的方式进行左向解析,则存在解析错误。
一旦解析器实现经过测试可以在测试用例上工作,那么“Hello World”应用程序的操作按钮实现就可以创建一个解析器来解析文本字段的文本,并将最终的数字结果作为标签的文本输出,从而实现一个计算器。其他小部件,比如 UISegmentedControl
,可以稍后用于实现计算器按钮。
- 再添加两个文本字段,使按钮操作向地址发送电子邮件,并附带主题和正文;
如果您正在为除 Mac 之外的其他平台开发,则可以使用命令行中的 GCC。GCC 是各种 GNU 编译器的集合。GCC 具有一个从命令行工作的 Objective-C 包。如果 GCC 安装正确,您应该能够链接到 Objective-C 运行时库;否则,您需要咨询您的软件包系统。
要使用 GCC 构建程序,您需要至少指定一个输入文件并将您的程序链接到 Objective-C 库。
gcc hello.m -lobjc
您可能想要使用额外的标志让编译器指出常见错误并抑制有关#import
关键字的警告。
gcc -std=c99 -pedantic -Wall -Wextra -Wno-import -lobjc -o hello hello.m
程序所需的任何其他文件或库都需要添加到命令行。此外,gcc 允许将 Objective-C 文件编译成中间文件,然后可以将这些中间文件链接到输出二进制文件。
gcc -c hello.m -o hello.o gcc hello.o -o hello
要使用 Objective-C 的面向对象功能,您需要在文件顶部放置以下代码。
#import <objc/Object.h>
一般来说,编译器名称为objc
,除非您的编译器另有指定。
在一般情况下,您需要在顶部添加以下内容以支持对象。
#import <Object.h>