1, 从简单的例程来看基本语法:
下面的代码是通过OSX-Application-Command Line Tool生成的:
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
NSLog(@"Hello, World!");
NSLog(@"Hello, Objective-c");
}
return 0;
}
1>,文件名:First_OSX_eg.m 这个是OC专用的扩展名,c语言的扩展名一般是用.c,库文件用.h;c++的扩展名一般用.cpp;
而OC的扩展名都是用.m(来自单词message)不过这个只是阐述部分的扩展名,声明部分的扩展名也是用.h,而且文件名与对应.m的文件是同名,如果扩展名为.mm则可以认为这个单元是c++代码(c++是兼容c的).
2>,#import相当于C语言中的#include,Delphi语言中的Uses,表示对库文件或其他单元的引用.虽然OC也兼容#include,但是#import要比#include好得多,不管你在文件中出现了多少次#import引用,编译器对特定文件就只引用一次.
#import之后所用的库文件,在语法上,使用双引号或者尖括号都是允许的,但是一般系统默认为双引号为本地头文件,
而尖括号里跟的时系统头文件.
3>,<Foundation/Foundation.h>表示引用Foundation框架中的Foundation.h文件.用花键+单点可以查看对应的单元文件.其实,在引用系统库时,一般头
文件都是几十上百个头文件的集合.#import可以预编译头文件,使得引用速度加快. 例如Foundation.h对应的框架文件可以在以下路径进行查看:
/System/Library/Frameworks/Foundation.framework/Headers/ (后面版本的Headers目录改成了Resources目录).
4>,NSLog函数,其中NS表示OSX中基础Cocoa库,最早引用于Next-Step架构,其意义和用法基本等同于C语言中的printf(),但是其参数需要一个Cocoa库
格式的字串.类似这样的NS命名的函数还很多,例如:
NSArray: 用来定义一个数组
NSDateFormat: 格式化日期
NSThread:定义一个线程.
NSSpeechSyntheSizer:定义一个声音.
5>,用@“xx”来表示一个字串,其中@的意义是指这个字串是一个Cocoa库中的NSString字串,而不是传统的C语言字串.作为一个Cocoa风格的字串,其功能
要比传统的C语言字串强大得多.例如用StringWithFormat方法就可以用格式化字符(例如%d)格式化各种类型数据.
6>,花+~可以很方便的在多个工程中切换.
2, 常用的OC对象类型:
1>,UIView : 所有可视控件的基类。基于此类的每一个对象都是一个容器。
2>,UILabel:标签类
3>,UITextField:文本输入类
4>,UIButton: 按钮类
3, 常用的OC语法:
1>程序流程控制
a>, 选择结构:
if(BOOL表达式)
{
表达式;
}
else
{
表达式;
}
b>,循环结构:
int i;
for(i=0; i<=99;i++)
{
NSLog(@“%d\n”,i);
}
或者
while(BOOL表达式)
{循环体}; //这个需要在循环体中对BOOL表达式进行控制.
c>,分支结构:
switch(表达式)
{
case 分支1数值: 表达式;
break;
case 分支2数值: 表达式;
break;
…
}
’ 2>, 函数定义:(注意,在Obj-c中,不允许在一个函数内部直接定义子函数.每个函数的作用范围自动是从
上至下,可以通过声明来作用全局,或者提供给其他单元接口),函数允许参数名与函数名同名.
如果函数的返回值类型为一个类的对象,则函数应该用指针型,例如:
NSString *ShowMsg(int x1)
{
return([NSString stringWithFormat:@"%d",x1]);
}
如果是调用这个函数返回值,可以用%@格式字串例如:
NSLog(@"%@",ShowMsg(123456));
关于默认的main函数定义:int main(int argc, const char *argv[])
其中,argc为程序的参数个数,argv为参数数组,其中argv[0]为程序文件本身路径+文件名(这点与Delphi相同).
3>, 数据类型的定义(对于对象的定义一律用指针)
a>, 整型: int a;
b>, 字符类型: char c;
c>, 字符串类型:
char s[n]; 这个相当于n长度的数组,而对应Cocoa库则为NSArray. 这里s即为一个指针,相当于字符串对象名.
char s[]; 可以这么定义一个变长的数组,Obj-c中的字符串严格按对象处理,不像Delphi中那么方便了.
可以用strlen(s)来返回一个字串的长度.
char *s[];可以用这个来定义一个多维数组,其中每一个s[i]对应一个字串.
NSString str; 不过由于Obj-c中常使用Cocoa库的NSString,所以大多数时候,尽量使用这个类型,它带有很多方便的方法.
d>,BOOL类型: OC的布尔类型并不是true和false,而是YES和NO. 其本质是一个8位的带符号的字符.定义时,1为YES,0为NO.在实际使用时,如果把其他符号
当作BOOL类型判断,那么只会判断其最低位的值,而忽略高位值(注意这里跟C语言不同,并不是大于0就为真).
对BOOL类型值的判断,只能拿值与NO进行比较,如果相当为假,不等则为真.无法用BOOL类型与YES进行比较(虽然有时候用YES比较也恰好正确).
e>,浮点型float
f>,常量关键字const 这个可以加在定义类型前,例如:const char *argv[];
g>,枚举类型的定义:
typedef enum{ 枚举常量列表,逗号隔开} 枚举类型名;
并没有具体的内部函数可以直接得到枚举常量名,可以自己构造一个函数来实现.
常用的枚举定义技巧,可以定义一个起始量和一个终止量,这样方便循环遍历.
h>,结构体类型定义:
typedef struct{结构体元素定义}结构体类型名;
对结构体赋值可以直接用大括号包含数值: stru1={1,’a’};
也可以用[结构体变量名.成员名]引用每一个成员进行赋值.
5>,更为复杂的一些Cocoa定义的有用数据类型.
a>NSRange:
typedef struct _NSRange{
unsigned int location;
unsigned int length;
} NSRange;
表示一段数据的起始位置以及数据长度.
可以利用快捷函数NSMakeRange()来返回一个NSRange
eg. NSRange range=NSMakeRange(17,4);
b>若干几何数据类型:NSPoint, NSSize,NSRect
对应快捷函数NSMakePoint(), NSMakeSize(),NSMakeRect()
typedef struct _NSPoint{
float x;
float y;
} NSPoint;
typedef struct _NSSize{
float width;
float height;
}NSSize;
typedef struct _NSRect{
NSPoint origin;
NSSize size;
}NSRect;
c> NSString, 相比c语言中的字符串与字符数组的关系,不需要再考虑0操作字符.
6>, 文件类型定义: FILE *words; words=fopen(argv[1],”r”);
上面这两句也可以在定义时直接赋值:FILE *words=fopen(argv[1],”r”);
fgets(word, 100, words); 这个函数用来读取一个文本文件内容,其中word为一个数组用来接收数据,100读取长度,words为文件类型.
其返回值为BOOL型,读取文件时,遇到换行符自动结束本次读取,并且将文件的位置标志置于下行开始.
可以用这个语句将读取的内容转为字符串:word[strlen(word)-1]=‘\0’; 反斜杠0是空操作字符用来表示字符串结束.
文件标准路径的写法:/Users/Murphy/…
每一个用户,均有以用户名命名的根目录文件夹结构,其对应的系统文件夹路径如下:
公共:/Users/用户名/Public
图片:/Users/用户名/Pictures
文稿:/Users/用户名/Documents
5,类与对象的使用
1> 类的定义,可以分为两个部分,一个部分是声明部分,一个部分是阐述部分:
//声明部分用来描述定义各个成员和方法,格式如下:
@interface 类名 :基类名 //这里基类名可以使用NSObject, 或者其他基类。
{
@public/@private/@protected //其实Obj-c并不存在真正的私有方法.这是Obj-c的动态本质决定的.
成员定义区;
}
@public/@private/@protect
方法定义区; //方法可以用加号或者减号来对应类方法或者成员方法.如果没有加减号,则是函数原型.
e.g. -(void) setmember : (类型)参数;
@end
’ //类的声明部分主要是针对其方法进行的,格式如下:
@implementation 类名
-(void)方法名 : (类型)参数
{
方法实现;
}
@end //类名 在结束符后,添加类名,是一个好的习惯,可以增加程序的可读性.
这里注意,方法的返回值也是需要类型定义的,一定要用加减号(类型)的形式来说明,括号不能省略.同样,参数的
类型圆括号也不能省略.
在@implementation中允许出现无声明的方法,这种方法可以看做是类私有方法(与Delphi相同).
在@implementation部分的参数名可以不与@interface部分相同.注意,在@implementation中使用的参数
最好不要与@interface部分的成员变量同名,否则会隐藏实例变量,并生成警告信息.
如果想调用隐藏的实例变量可以用self->成员名来进行.
2>类和对象的使用语法:
a> 在Obj-c中,所有对象的原基类都是NSObject,(这相当于Delphi中的Object).
b>Obj-c中的所有成员变量的定义,均是 类型名在前,变量名在后.并且在定义的时候就可以直接赋值.
c>Obj-c的中缀符调用方法:
[对象名 方法名: 参数];
这里方法名和冒号可以看成是一体的,它告诉编译器后面会出现参数.而在不含参数的方法后面添加冒号会报错.
d>类的公共接口称为API(application programming interface)
e>在方法体中,允许使用self来访问对象本身.
f>NSObject类具有一个类方法new,(相当于Delphi的构造方法).我们可以通过调用这个方法得到一个实例.
[类名 new]; // 当然所有类方法,都可以用向类名发送消息的方法进行调用.
g>id 可以用来定义一个通用对象变量,它可以指向任何对象,并且可以用id 来定义一个数组,然后每个数组元素
都指向不同类的对象. //这里有个疑问,为什么不直接用NSObject代替id,不过我好好研究了下,发现id跟Delphi
中引用Object还真是不同,id 定义的对象,你可以直接向它发送各种子类消息,而不需要用as 进行类转换.
3>类继承的实现:
a>Obj-c废弃了C++多继承的特性,在Obj-c中是不允许多继承的.(这点跟Delphi是一样的).
b>Obj-c在声明的时候,是没必要像Delphi那样用virtual或者dynamic来声明虚函数的.
只需要在子类覆盖此方法的时候,在阐述部分使用super关键字,即可完成继承.其调用父类部分格式为:
[super 方法名称:参数]; //即完成了对父类虚方法的调用,类似Delphi中的inherited; 但是这个语句是写在覆盖
函数之外的.
super关键字,会沿着超类链持续往上级查找,直到找到父类的方法.
4>类的复合:
将若干个对象组合在一起,并且形成一个新对象的过程就叫复合.
每一个组合子对象都可以看作是母对象的一个属性,而对每个属性都可以用同名的getter和setter方法来进行
存储,一般都是成对出现,其格式如下:
-(子对象类*) 子对象名; //这里省略掉了对应的get关键字,除非getter方法需要用到指针形参才会添加get
-(void) set子对象名:(子对象类型*) new子对象名; //这里的形参最好不要与原对象同名,
set后跟的对象名,第一个字母一般习惯大写.
注意,当使用setter方法进行属性设置时,被替代的数据其实是属性的指针,而不是真实值.由于Obj-c的对象引用
机制,我们不需要考虑到这里的主动释放,这跟Delphi是不同的.
属性的自我构造,可以使用init函数来实现,在定义属性类中,用以下语句可以实现属性对象的自我构造:
注意init方法属于对象的内部方法,是不需要在@interface部分主动声明的.
@implementation 母对象名
-(id)init
{
if(self=[super init]){
属性名=[属性类名 new];
}
return(self);
}//init
…
@end
这样就形成了属性的自我构造,不过如果属性有相应的setter方法,其实不用构造也可以,不过使用时需要主动赋值.
5>头文件的拆分,指向,导入和继承:
在用.m文件和.h文件拆分复合类时,需要在复合类的头文件中用 @class 类名 指向其复合的属性类.
而在复合类的阐述文件中,不仅仅要用#import导入其对应头文件,也必须用其导入对应的所有属性类的头文件.
而在派生类拆分文件时,派生类的头文件,只需要导入父类的头文件就可以(可以完全忽略父类中已有的系统头文件)
6>面向对象的设计意义:
a>在面向对象和面向过程的设计中,最大得差别是其功能修改增删时的改变方式.面向对象可以避免修改到整体
的处理函数,也不需要修改基本的结构体,只需要增加一个类基本就可以适应变化了.
b>面向过程的设计是函数第一,数据第二,这导致程序修改经常会影响到接口;而面向对象的设计,可以直接吧原先
函数修改的部分巧妙的移动到对象的方法之中,我们只需要关注对象这个数据就好了,不会影响到函数和接口.
c>当不同类中出现了大量的重复的代码,就绝非优良的设计,我们可以更改其类的继承结构,使这些重复代码在中间
的继承类中实现,这种移动和简化代码的方法称为重构.
d>当你创建的新类与现有类是is a 的关系就可以使用继承;当你创建的类与现有类是has a 的关系,就需要用到复合了.
7>面向对象的术语:
a>超类:superclass
b>父类:parentclass,同超类.
c>子类(派生类):subclass
d>孩子类:childclass,同子类.
6,常用的XCode操作技巧
1>花+[ 和 花+]可以将选定得代码块左移或者右移
2>ESC键可以关闭和打开自动完成的选择框.
3>Control+/ 可以在输入时自动跳在占位符上.
4>花+Control+S可以建立一个快照.
5>花+Shift+O 快速打开一个单元文件.
6>Control+F/B 分别是前移光标和后移光标.
7>Control+P/N 分别是上移光标和下移光标.
8>Control+A/E 分别是移动光标到该行的行首和行尾.
9>Control+T 把光标前的字符往后拖一个位置.
10>Control+D 删除光标右边的字符(相当于windows中的Del键).
11>Control+K 删除一行.其实这个是删除当前行光标后面的部分.
12>Control+L 调整窗口,以便将当前的光标居于窗口中心.
13>花+Y 以调试方式运行程序.
14>花+Option+P/O/I/T 分别是调试的 继续,跳过,跳入,跳出.