1、首先,什么是Objective-C?
Objective-C是一门基于C语言的面向对象语言,C语言的基础上,增加了一层最小的面向对象语法,完全兼容c语言,它在现代计算机的主要作用于Mac OS X作为桌面语言以及作用于iPhone OS(亦称:iOS)。它原是NeXTSTEP 操作系统的主要语言,NeXTSTEP OS随后被苹果公司收购,并派生出Mac OS X,所以这可以很好地说明今天的苹果操作系统和它有异曲同工之妙。
由于Objective-C是C语言的一个严格超集,所以我们可以在Objective-C文件里自由地使用C语言并会顺利编译通过。因为任何Objective-C的编译器会将C代码编译过去,也就是说,我们拥有通过Objective-C实现C的面向对象能力。
那也就是说C能做的,Objective-C都能做,但反过来不成立。
苹果公司把Mac操作系统上的整个开发环境命名为Cocoa,在Cocoa上,开发语言是 Objective-C,开发工具是Xcode等。苹果公司专门提供了iPhone/iPad软件开发包,这个开发包提供了很多框架(Framework),从而帮助开发人员快速地开发应用程序。
2、学习OC必须要有一定的C的基础,那是因为:
1) OC基于C
2) OC跟C的思想和语法很多地方不太一样,而且OC能和C混用
3) C是所有编程语言中的经典,很多高级语言都是从C语言中衍生出来的,比如C++、C#、Objective-C等
C程序的运行过程主要分为以下几个部分:
编译:
1) 什么是编译:将C源程序翻译成计算机能识别的0和1
2) 使用什么编译器:Xcode3使用GCC,Xcode4使用LLVM编译器(前端用clang)
3) 如何使用clang编译器编译程序?
在终端中输入:cc –c 文件名.c
编译成功,会生成.o目标文件
4) 编译器的错误和警告功能
如果代码有语法问题,编译器会直接报错。并指出错误的个数和具体行号。
只要有1个错误,程序就不能编译成功,也不会生成.o文件
警告信息只是编译器的一些建议,并不影响编译通过
1) 链接的作用:将.o文件和C语言函数库组合在一起,生成可执行文件
2) 由链接器完成,clang编译器里面已经包含了链接指令
在终端中输入:cc 文件名.o
链接成功,会生成a.out可执行文件
运行:
1) 两种运行方式
直接双击打开a.out文件
终端中使用 ./a.out指令
2) 修改文件内容之后,一定要重新编译、链接,再运行
3) \n的作用:回车换行
C程序编写执行过程:
1、 编写代码
2、 编译:把C语言代码翻译成0和1
工具:clang 编译器(Xcode3 gcc Xcode4 LLVM(clang))
安装命令行工具
指令:cc -c 文件名.c (compile)
编译成功,会生成一个.o目标文件
3、 链接:其实就是把.o目标文件跟系统自带的函数库合并在一起,生成一个可执行文件
链接器
指令:cc 文件名.o
4、 运行
a.out,生成a.out 文件,打开方式两种,一种是./ a.out 回车,另一种是双击执行就可以了
-o 文件名就可以改文件名,改a.out 改为其他名字
总结常见文件的拓展名
.c是C语言源文件,在编写代码的时候创建
.o是目标文件,在编译成功的时候产生
.out是可执行文件,在链接成功的时候产生
.h是头文件,头文件包含类、类型、函数和常量声明
.m实现文件。具有此扩展名的文件可以同时包含OC代码和c代码,有时也称源文件
.mm实现文件。具有此拓展名的实现文件,除了包含OC代码和c代码以外,还可以包含C++代码,仅当实际引用OC代码中的C++类或功能时,才使用此拓展名
2) 总结clang指令
编译:cc –c xxx.c
链接:cc xxx.o
编译、链接:cc xxx.c
运行可执行文件:./a.out
3、对于Mac系统与Windows系统的一些常用习惯的区别:
Mac常用快捷键:
文件操作
复制:Command + C
粘贴:Command + V
回退:Command + Z
保存:Command + S
窗口操作
关闭窗口:Command + W
退出程序:Command + Q
管理多个桌面:Ctrl + ↑
切换程序窗口:Command(长按) + tab
切换输入法:Command(长按) + 空格
Mac的文件系统:
Mac系统采用的是UNIX文件系统,所有的文件都放在根目录/下面,因此没有Windows中分C盘、D盘的概念,文件路径就不再有盘符
Windows中 c:/users/mj/desktop
Mac中 /users/mj/desktop
常见文件夹
用户的个人文件夹(apple是用户名):/Users/apple
桌面:/Users/apple/Desktop
文稿:/Users/apple/Documents
下载:/Users/apple/Downloads
应用程序:/Users/apple/Applications
常见Unix指令:
因为Mac系统是基于UNIX系统的,因此可以在“终端”中输入一些UNIX指令来操作Mac系统。比如:新建文件\文件夹、打开文件\文件夹
常用的UNIX指令:(需要经常使用才不容易忘记)
ls –l 列出当前目录下的所有内容(文件\文件夹)
pwd 显示出当前目录的名称
cd 改变当前操作的目录
who 显示当前用户名
clear 清屏
mkdir 新建一个目录
touch 新建一个文件(文件不存在才会新建)
open 打开一个文件\文件夹
按一下tab键,可以自动补齐指令名称、文件名、文件夹名等
(上述指令均可以在百度上搜索到具体用法)
Unix指令中的特殊路径:
在使用Unix指令过程中,经常会涉及到目录(路径)操作,下面列出几个有特殊含义的路径:
/ 根路径
./ 当前路径
../ 上一级路径
4、关于C的一些小细节:
返回值:
Return的作用:
1、 退出函数
2、 返回一个具体值给函数调用者
Void:
没有返回值
返回值注意点:
1、 void代表没有返回值
2、 如果不声明返回值类型,默认就是int 类型。
3、 就算明确声明了返回值类型,也可以不返回任何值。
默认情况下,C语言不允许两个函数的名字一样
函数注意点:
1、 默认情况下,不允许函数名称一样
2、 函数不能嵌套定义
3、 函数不能重复定义,但是可以重复声明
4、 如果有函数的声明,没有函数的定义
函数编译可以通过,因为编译器只会检测语法合不理,并不会检测函数有没有定义
链接会报错,因为链接的时候会检测函数是否定义
include 作用:
1、 拷贝右边文件夹的所有内容到#include所在的位置。
2、 自定义的文件用””,系统自带的文件用<>
3、 #include<stdio.h>的目的:拷贝printf函数的声明
import 的用途:
(1)跟#include一样,拷贝文件的内容
(2)可以自动防止文件的内容被重复拷贝
函数的定义放.c文件,函数的声明放.h文件
如果要使用某个.c文件中定义的函数,只需要#include这个.c文件对应的.h文件
.h文件的作用:被别人拷贝,编译链接的时候不要管.h文件
数组作为函数参数,可以省略元素个数
数组作为函数参数,传递是整个数组的地址,修改函数形参数组元素的值,会影响到外面的实参数组。
数组当做函数参数传递时,会当做指针变量来使用,指针变量在64bit编译器环境下,占据8个字节
%d: int
%f:float/double
%ld:long
%lld:long long
%c:char
%s:字符串
%zd:unsigned long
5、关于OC的细节总结:
OC程序的开发过程:
终端指令:
编译cc –c main.m
链接cc main.o –framework Foundation
运行./a.out
NSLog与printf的区别:
NSLog接收OC字符串作为参数,printf接收C语言字符串作为参数
NSLog输出后会自动换行,printf输出后不会自动换行
使用NSLog需要#import <Foundation/Foundation.h>
使用printf需要#include <stdio.h>
1、import 的用途:
(1)跟#include一样,拷贝文件的内容
(2)可以自动防止文件的内容被重复拷贝
2、#import<Foundtion/NSObjCRuntime.h>
NSObjCRuntime.h中有NSLog函数的声明
3、主头文件:
(1)主头文件:最主要的头文件,名字一般跟框架名称一样,包含了框架中所有的其他头文件
(2)Foundation框架的主头文件名称就是Foundation.h
(3)只需要包含Foundation框架的主头文件,就可以使用整个框架的东西
4、运行过程:
(1)编写OC源程序:.m 、 .c
(2)编译:cc -c xxx.m xxx.c
(3)链接: cc xxx.o xxx.o -framework Foundation
(只有用到了Foundation框架才需要加上-framework Foundation)
(4)运行: ./a.out
面向对象与面向过程的区别:
1、以电脑听歌为例:
(1)面向过程:
打开电脑 播放电脑的歌曲 关闭电脑
(2)面向对象:
电脑 (开机 播放歌曲 关机 )
区别分析:
面向过程关注的是解决问题需要哪些步骤,面向对象关注的是解决问题需要哪些对象
现实生活中面向对象的例子:
想打电话\发短信 找手机,不用分析电话要怎样才能拨通
去饭店吃饭 找服务员,不用分析怎么到厨房炒菜
汽车坏了 找汽车维修工,不用分析修车的步骤
境界:万物皆对象
类和对象的关系:
1) 现实生活的例子:如何创造汽车对象?
a) 需要先有汽车的建造图纸,图纸上描述清楚汽车应该具备的属性和功能(行为)
属性:轮子数、时速
功能(行为):跑
b) 然后再根据图纸上的描述生成汽车
c) 每一辆汽车都是对象,都有自己具体的属性值,都是图纸的实例
d) 图纸是抽象的,房子是具体的。图纸是对房子对象的高度概括
1. OC中的面相对象
1) OC中的类相当于图纸,用来描述一类事物。也就是说,要想创建对象,必须先有类
2) OC利用类来创建对象,对象是类的具体存在
3) 因此,面向对象解决问题应该是先考虑需要设计哪些类,再利用类创建多少个对象
2. 需要设计哪些类,如何设计类
1) 类的设计,只关心3样东西:
事物名称(类名):人(Person)
属性:身高(height)、年龄(age)
行为(功能):跑(run)、打架(fight)
2) 一般名词都是类
坦克发射3颗炮弹轰掉了2架飞机
小明在公车上牵着一条叼着热狗的狗
3) 拥有相同(或者类似)属性和行为的对象都可以抽像出一个类
类的设计:
1、 类名
(类名的第一个字母必须大写,不能有下划线,多个英文单词,用驼峰标识)
2、 属性
3、 行为(功能)
植物大战僵尸的僵尸:
1、 僵尸
类名:JumpZoobie
属性:life、speed、 gongjili
行为:walk、 bite、die
雷电的飞机:
类名:Plane
属性:life、gongjili、speed、bombCount
行为:fly、bomb、shoot、die
常用术语
面向过程 ProcedureOriented
面向对象 ObjectOriented,简称OO
面向对象编程 ObjectOriented Programming,简称OOP
5、定义OC的类和创建OC对象:
类的声明
1) 代码编写
定义一个Car类,拥有2个属性:轮子数、时速,1个行为:跑
类名\属性的命名规则:标示符的规则
类名的命名规范:有意义、驼峰标识、首字母大写
#import <Foundation/Foundation.h>
// 类的声明
@interface Car : NSObject
{
@public
int wheels; // 多少个轮子
int speed; // 时速
}
- (void)run; // 跑的行为
@end
2) 成员变量
@interface的大括号{}中声明的变量:wheels、speed
@interface的大括号和函数的大括号是不一样的
默认会初始化为0
3) @public
@public可以让Car对象的wheels和speed属性被外界访问
4) NSObject
加上:NSObject的目的是让Car类具备创建对象的能力
类的实现
// 类的实现
@implementation Car
- (void) run
{
NSLog(@"%i个轮子,%i时速的车子跑起来了", wheels, speed);
}
@end
创建对象
1) 代码编写
// 主函数
int main()
{
// 创建车子对象
Car *c = [Car new];
c->wheels = 3;
c->speed = 300;
[c run];
return 0;
}
2) main函数的代码分析、内存分析(对象在内存中有成员)
[Car new]每次都会创建出新的对象,并且返回对象的地址,那么就应该用一个指针变量保存对象的地址
Car *c = [Car new];
用一个指针变量c指向内存中的Car对象
设置车子对象的属性
跟用指向结构体的指针访问结构体属性一样,用->
c->wheels = 3;
c->speed = 300;
创建多个Car对象
分别只设置wheels、speed属性
Car *c1 = [Car new];
c1->wheels = 4;
Car *c2 = [Car new];
c2->speed = 250;
[c1 run];
1个赋值给另一个,然后修改属性
Car *c1 = [Car new];
c1->wheels = 4;
c1->speed = 250;
Car *c2 = c1;
c2->wheels = 3;
[c1 run];
面向对象封装的好处
更加接近人类的思考方式
只需要关注对象,不需要关注步骤
对象与函数参数
对象成员变量作为函数参数
指向对象的指针作为函数参数
修改指向指向对象的成员
修改指针的指向
@interface就好像暴露在外面的时钟表面
@implementation就好像隐藏在时钟内部的构造实现
OC方法和函数的区别
OC方法只能声明在@interface和@end之间,只能实现在@implementation和@end之间。也就是说OC方法不能独立于类存在
C函数不属于类,跟类没有联系,C函数只归定义函数的文件所有
C函数不能访问OC对象的成员
低级错误:方法有声明,但是实现的时候写成了函数
OC的方法注意
方法只有声明,没有实现(经典错误)
方法没有声明,只有实现(编译器警告,但是能调用,OC的弱语法)
编译的时候:访问没有的成员变量直接报错,访问没有的方法,只是警告
@implementation
没有@interface,只有@implementation,也是能成功定义一个类的
@implementation Car : NSObject
{
@public
int wheels; // 多少个轮子
int speed; // 时速
}
- (void) run
{
NSLog(@"%i个轮子,%i时速的车子跑起来了", wheels, speed);
}
@end
@implementation中不能声明和@interface一样的成员变量
方法:
不带参数的方法:
方法调用:
带一个参数的方法:
方法调用:
带多个参数的方法:
方法调用:
方法名注意
冒号也是方法名的一部分
同一个类中不允许两个对象方法同名
一个小例子的引入:
例:
/*
类名:Car
属性:轮胎个数、时速(速度)
行为:跑
*/
//完整地写一个函数:函数的声明和定义(实现)
//完整地写一个类:类的声明和定义
//因为使用了NSObject
#import <Foundation/Foundation.h>
//类的声明
//声明对象的属性、行为
// : NSObject 目的是:让Car这个类具备创建对象的能力
@interface Car : NSObject
{//用来声明对象属性(实例变量\成员变量,默认初始化为0)1
//@public可以让外部的指针直接访问对象的内部的成员变量
@public
int wheels;//轮胎个数
int speed;//时速(xxkm/h)
}
//方法(行为):方法名、参数、返回值(声明、实现)
//只要是OC对象的方法,必须以减号-开头
//OC方法中任何数据类型都必须用小括号()扩住
-(void) run; //OC方法中的小括号():扩住数据类型,没有数据类型不要写
@end
//类的实现
//用来实现@interface中声明的方法
@implementation Car
//方法的实现(说清楚方法里面有什么代码)
-(void)run
{
NSLog(@“车子跑起来了”);
}
@end
int main()
{
//利用类来创建对象,在OC中,想执行一些行为,就写一个中括号[行为执行者 行为名称]
//执行了Car这个类的new行为来创建对象
//定义了一个指针变量p,p将来指向的是Car类型芙蓉对象
//[Car new]会创建一个新的对象,并且返回新的对象本身(新对象的地址)
Car *p = [Car new];
Car *p2 = [Car new];
p2->wheels = 5;
p2->speed = 300;
[p2 run];
//给P所指向对象的wheels属性赋值
p->wheels = 4;
p->speed = 250;
//OC中对象只能通过指针来实现
//给p所指向对象发送一条run消息
[p run];
NSLog(@"车子有%d个轮子,时速为:%dkm/h",p->wheels,p2->speed);
return 0;
}