<html>
怎样依据题目准确完整清晰的声明一个类并实现给定的行为
/*
//以下这个程序教大家怎样依据题目去声明一个类。并完毕题目中描写叙述的行为。怎样让代码表示的准确清晰。
类名:Person
属性:年龄(_age)、体重(_weight)
动作:吃饭(eat)方法、散步(walk)方法
功能:人能够吃各种食物。体重均+0.6
//分析一下这个功能,人能够吃各种食物。说明仅仅要吃食物就添加。所以我们应该定义一个方法參数来接收食物的信息,显然应该定义成NSString * 类型的
每次散步100。让体重-0.2。小于100体重没变化
//这个功能与什么相似呢?显然是向下取整,也就是整除。让散步的步数除以100。得到的是几就用几去乘以0.2,也就是体重的降低量
*/
/*
#import <Foundation/Foundation.h>
@interface Person : NSObject
{
@public //每次都要提醒。一定要将属性(成员)设置成public类型的
NSString *_name;
int _age;
float _weight;
}
-(void)eat:(NSString *) FoodName; //记住。声明定义方法的时候一定要让方法清晰易懂,可读性高,而且将题意分析的透彻,參数能够多加非常多个。仅仅要是题意须要,能够任意设置对应类型的參数
-(void)walk:(int)step;
@end
@implementation Person
-(void)eat:(NSString *) FoodName
{
_weight+=0.6;
NSLog(@"%@吃了%@体重变为%.2f",_name,FoodName,_weight);
}
-(void)walk:(int)step
{
_weight-=step/100*0.2;
NSLog(@"%@走了%d步体重变为%.2fkg",_name,step,_weight);
}
@end
int main()
{
@autoreleasepool {
Person *p=[Person new]; //每次都要提醒,实例化一个类的实例对象的时候一定要是指针类型!!。
p->_name=@"lalala";
p->_weight=55.8;
[p eat:@"chicken"];
[p walk:233];
[p walk:99];
}
return 0;
}
*/
———————————————————————————————————————————
对象的存储细节说明
/*
//[Person new] 做了3件事情
// 1) 申请内存空间
// 2) 给实例对象初始化
//初始化的时候:
//假设实例变量是基本数据类型,此时给初始化为 0
//假设实例变量是OC字符串类型。则初始化为 null
// 3) 返回(堆)空间的首地址
//1、申请的空间在内存的哪个区?
// new 的时候申请的空间在内存的堆区(程序动态分配的内存空间)
//2、实例变量又保存在什么地方
// 堆区(实例对象的详细属性)
// p(指针变量,也就是我们实例化的对象) 存放在栈区
//3、对象方法保存在什么地方
// 代码区。
要记住,类的全部对象 共用 类的方法。类的方法在内存中仅仅有一份
//4、为什么使用 [p run]; 就能够调用方法了 ?怎样调用的
// 首先找 指针变量p 指向的相应的堆区的空间。然后找到 _isa指针,再找到_isa指向的代码区的空间,然后到该空间中找 方法,继而调用代码区空间的方法。
(isa的起始地址和对象的起始地址值是一样的,而isa在NSObject中被声明为一个指针,MAC OS系统是64位的,所以指针也就是64的。即占8字节空间。
也就是说实例对象開始前8字节就是isa指针)
//5、一个类能够创建多个对象,而且他们互不影响
*/
上面这个图对上面的存储模式作了非常形象的展示。
———————————————————————————————————————————
#pragma mark指令的使用
功能:即对代码的分组,方便查找和导航。
上图 No Selection 部分被挡到了,在以下又截了一下
从上面两图可知,我们在No Selection中能够看到我们这个代码的导航,能够精确的找到哪一行的所在位置。可是还是略显不清晰。那么我们就须要用到 #pragma mark 预处理指令。他能在导航里加入必要的文字和横线进行代码块的区分。
另外须要小小的提示一点,对于 #pragma mark - 这条预处理指令,显然他是显示一条横线,可是注意不要在这条语句后面加多余的空格,否则表面可能没有变化。可是在查找搜索的时候。会多显示一行横线,例如以下图:
———————————————————————————————————————————
函数 和 对象方法 的差别
首先我们先简单认识一下。
对象方法(动态方法):
-(void)eat;
1)对象方法的实现仅仅能写在 @implementation … @end 之间。对象方法的声明仅仅能写在 @interface … @end 之间
2)对象方法都以 - 号开头,而类方法(静态方法)都以 + 开头
3)对象方法仅仅能由对象来调用。
同理。类方法仅仅能由类来调用。而都不能当作函数一样调用。
4)对象方法归 类/对象 全部
函数:
void run()
{
}
1)函数属于整个文件的,能够写在文件里的不论什么位置,包含 @implementation … @end 之间。可是写在 @interface … @end 之间无法识别。同C语言一样,函数的声明能够写在main函数的内部也能够写在main函数的外部。
2)全部函数都是平行的
3)使用的时候能够直接调用
4)函数没有隶属关系
5)函数不能够訪问对象中的成员变量
这一部分纯理论知识,大家假设对里面的某些地方不懂。或者不信任。那么能够去简单的验证一下,也不麻烦~
———————————————————————————————————————————
常见错误的汇总
这一部分刚開始学习的人常错,能够着重看看。这一部分非常easy,主要是用心细心。
重点我已经用“★”标记,读者重点去看看。
1)★★@interface @end 和 @implementation @end 是不能嵌套的。不能把方法的实现keyword夹在声明的keyword中间
2)@end不要漏写
3)成员变量(属性),写在大括号中
4)★方法的声明 不要 写在大括号中
5)★★★声明的同一时候不要对成员变量初始化。这里怎么理解呢?那就是,成员变量(实例对象的详细属性)不能脱离对象而独立存在
6)★★方法无法和函数一样调用
7)★★★成员变量和方法不能用static等等keyword修饰,修饰他们一般用到的是public、protect这些keyword
8)★★★类的实现部分,也就是@implementation … @endkeyword及当中间包括的方法实现部分,能够写在main函数的后面。可是@interface … @endkeyword及当中间包括的类的声明部分。是必须写在main函数的前面的
9)★★假设有多个类,声明和实现部分顺序是能够打乱的。可是声明部分一定要在实现部分的前面
10)★★★★★最后一点,也是最最重要我要说明的。就是在应用@try @catch @finally语句中的时候。捕捉错误信息的代码是怎么写的。
我们知道,@trykeyword后面是写可能会出错的代码,@catchkeyword后面是写出错之后我们须要处理运行的代码。@finally后面是写无论错误出错与否,都运行的代码。关键来了,就在catch后面,我们能够在后面加上一句 NSLog(@“%@”,exception);
这样就能够输出出错的信息了!
大家能够去尝试执行一下以下的程序,然后有助于理解第10条。
#import <Foundation/Foundation.h>
@interface Car : NSObject
{
@public
NSString *name;
}
-(void)run;
@end
@implementation Car //错误是:程序没有实现run这种方法
@end
int main()
{
@autoreleasepool {
Car *car=[Car new];
@try {
[car run];
}
@catch (NSException *exception) {
NSLog(@"wrong!");
NSLog(@"%@",exception);
}
@finally {
NSLog(@"123456!");
}
}
return 0;
}
这个程序的输出信息是:
2015-07-30 18:18:14.709 OC_program[9692:1739913] -[Car run]: unrecognized selector sent to instance 0x1002069c0
2015-07-30 18:18:14.710 OC_program[9692:1739913] wrong!
2015-07-30 18:18:14.710 OC_program[9692:1739913] -[Car run]: unrecognized selector sent to instance 0x1002069c0
2015-07-30 18:18:14.710 OC_program[9692:1739913] 123456!
大家能够參考一下!
———————————————————————————————————————————
对象和方法之间的关系
有两种关系:①对象作为方法的參数 ②对象作为方法的返回值(分别在以下用两个对象方法来进行说明)
#import <Foundation/Foundation.h>
typedef enum {sMan,sWoman,sYao} Sex; //新建一个枚举类型Sex,那么自然三个相应的表示数字为 0 1 2
@interface Person : NSObject
{
@public
NSString *_name;
Sex _sex;
}
-(void)displayPerson:(Person *)person;//这种方法来验证对象作为方法的參数
-(Person *)changeSex:(Person *)person1;//这种方法来验证对象作为方法的返回值(当然在这种方法里面。对象也作为了此方法的參数)
@end
@implementation Person
-(void)displayPerson:(Person *)person//这种方法来验证对象作为方法的參数
{
NSLog(@"Name:%@,Sex:%d",person->_name,person->_sex);
}
-(Person *)changeSex:(Person *)person//这种方法来验证对象作为方法的返回值(当然在这种方法里面,对象也作为了此方法的參数)
{
person->_sex=sYao;//将性别_sex都改为sYao
return person;//我们最好还是让返回值就是person
}
@end
int main()
{
@autoreleasepool {
Person *p=[Person new];
Person *p1=[Person new];
p1->_name=@"Wang";
p1->_sex=sMan;
Person *p2=[Person new];
p2->_name=@"Ma";
p2->_sex=sWoman;
[p1 displayPerson:p1];//将p1作为方法的參数传进去(p1就是实參),返回p1的信息。
这里要注意,对象方法仅仅能由对象来调用,所以要先用p1调用这种方法,然后再将p1的值传进去。
看起来有点别扭。可是应该这么写。
[p displayPerson:p2];//当然,我们能够用一个不相干的实例对象p来调用这个对象方法。然后再传入p2。这样也能够的。
显然,p仅仅是一个实例对象,而我们并没有对其属性初始化
Person *p3=[p changeSex:p1];//这里实例化了一个实例对象p3来接收返回值。然后用实例对象p去调用了changSex这个对象方法,传入的參数是对象p1。然后对p1进行性别的更改,最后将更改完的新的p1返回,将返回值赋给p3
NSLog(@"Name(p3):%@,Sex(p3):%d",p3->_name,p3->_sex);//输出p3的属性
}
return 0;
}
———————————————————————————————————————————
类的对象与对象方法之间关系(题目)
//以下的题目结合起来写了一下,有两个地方须要注意:
//①在一个类的属性成员声明的时候,里面能够存在其它我们自己定义的类类型的实例对象作为其属性成员
//②假设用一个类的实例对象去调用他的对象方法的时候,当中用到了还有一个自己定义类类型的实例对象可是却没有赋值,那么也是能够调用并不会出错。仅仅是不会得到想要的结果罢了(没有结果),以下有介绍。
/*
1.设计一个”狗“类
1> 属性
* 颜色
* 速度(单位是m/s)
* 性别
* 体重(单位是kg)
2> 行为
* 吃:每吃一次。体重添加0.5kg。输出吃完后的体重
* 吠(叫):输出全部的属性
* 跑:每跑一次,体重降低0.5kg,输出速度和跑完后的体重
* 比較颜色:跟别的狗比較颜色,假设一样。两个值做减法得零,返回NO(零值)。不一样,做减法得到非零值。返回YES(1)
* 比較速度:跟别的狗比較速度,返回速度差(自己的速度 - 其它狗的速度)
2.结合前面的“狗”类,设计一个“人”类
1> 属性
* 姓名
* 狗(养了一条狗)
2> 行为
* 喂狗:每喂一次。狗就会运行“吃”这个行为
* 遛狗:每溜一次,狗就会运行“跑”这个行为
*/
#pragma mark 整个程序
#import <Foundation/Foundation.h>
typedef enum {dColorBlack,dColorWhite,dColorFlower,dColorGreen}Color;
typedef enum {dSexGong,dSexMu,dSexYao}Sex;
#pragma mark -
#pragma mark Dog类的声明
@interface Dog : NSObject
{
@public
Color _color;
int _speed;
Sex _sex;
float _weight;
}
-(void)eat:(NSString *)foodName;
-(void)bark;
-(void)run;
-(Boolean)isCompareColorWithOthers:(Dog *)dog2;//这里也能够用BOOL类型的返回值。看两仅仅狗的颜色是否一样。一样返回1。不一样返回0。
当然这里传入的參数是类类型(Dog类)的实例对象。
-(int)isCompareSpeedWithOthers:(Dog *)dog2;//题意。比較的是速度,然后返回速度差。自然是int类型的
@end
#pragma mark -
#pragma mark Dog类的实现
@implementation Dog
-(void)eat:(NSString *)foodName
{
_weight+=0.5;
NSLog(@"狗吃了%@,体重变为%.2f",foodName,_weight);
}
-(void)bark
{
NSLog(@"color:%d,speed:%d,sex:%d,weight:%.2f",_color,_speed,_sex,_weight);
}
-(void)run
{
_weight-=0.5;
NSLog(@"遛狗,体重变为:%.2f",_weight);
}
-(Boolean)isCompareColorWithOthers:(Dog *)dog2 //这里用BOOL类型也是能够的
{
if (_color==dog2->_color) {
return TRUE;
}
else
return FALSE;
}
-(int)isCompareSpeedWithOthers:(Dog *)dog2
{
return _speed-dog2->_speed;
}
@end
#pragma mark -
#pragma mark Person类的声明
//注意一下,我们在写Person这个类的时候。Person这个类中有属性成员是Dog类的实例变量。那么我们须要在这里“认识”Dog这个类,所以要把Person类声明在Dog类的以下。当然仅仅是声明。类的实现先后顺序能够任意。这个知识点在前面一节常见错误的汇总中提到过。
@interface Person : NSObject
{
@public
NSString *_name;
Dog *_dog; //在类的声明里面,其属性成员能够是其它我们定义的类类型的实例变量。
}
-(void)weigou:(NSString *)foodName;
-(void)liugou;
@end
#pragma mark -
#pragma mark Person类的实现
@implementation Person
-(void)weigou:(NSString *)foodName
{
[_dog eat:foodName];
}
-(void)liugou
{
[_dog run];
}
@end
#pragma mark -
#pragma mark main函数
int main()
{
@autoreleasepool {
Dog *dog1=[Dog new];
dog1->_color=dColorBlack;
dog1->_sex=dSexGong;
dog1->_speed=30;
dog1->_weight=60.5;
Dog *dog2=[Dog new];
dog2->_color=dColorBlack;
dog2->_sex=dSexMu;
dog2->_speed=40;
dog2->_weight=40;
[dog1 eat:@"humbugers"];
[dog1 bark];
[dog1 run];
Boolean b1=[dog1 isCompareColorWithOthers:dog2]; //这个对象方法包含以下的对象方法都须要声明一个与其返回值同类型的变量来接收其返回值。并输出。
NSLog(@"颜色是否一样:%d",b1);
int i1=[dog1 isCompareSpeedWithOthers:dog2];
NSLog(@"速度差:%d",i1);
#pragma mark 第二个题中的重点注意代码
Person *person1=[Person new];
person1->_name=@"Wang";
person1->_dog=dog1; //我们这里将dog1给了person1这个实例变量。那么以下的person1调用weigou和liugou的成员方法就有意义了。
当然假设是不给person1的Dog属性赋值,也没有错,null值也是能够运行的。仅仅是不会输出什么,没有得到预想的结果。
[person1 weigou:@"hotdog"];
[person1 liugou];
}
return 0;
}
———————————————————————————————————————————
对象作为对象方法的參数连续传递
//对象作为方法的參数连续传递。一个题来解释这个问题。说实话,这部分非常easy,尽管题目啰嗦,可是就是说了一个事儿
//有两个方法。一个是士兵开枪,另外一个是枪射击子弹。
士兵开枪须要用到子弹,然后还须要用到枪射击子弹这种方法。而枪射击子弹又要用到子弹,所以说子弹这个对象在两个方法中都用作參数传递了,所以叫对象作为方法的參数连续传递
//再缕一遍,第一个类的对象方法使用了第二个类和第三个类的实例对象作为參数,而在第一个类的对象方法体内让第二个类的实例对象去调用第二个类的对象方法,而第二个类的对象方法又相同使用了第三个类的实例对象作为參数。所以说,这么一个简单的程序。让第三个类的实例对象两次作为对象方法的參数出现。这也就是对象作为方法的參数连续传递
/*
士兵开枪 枪射击子弹
枪类:
名称:Gun
属性:型号(_size),子弹个数(_bulletCount)
行为:射击
人类
名称:Soldier
属性:姓名(_name) life level(等级)
行为:跑 蹲 开枪 跳
子弹类(弹夹)
名称:Bullet
属性:子弹个数。型号(_model)
//要求士兵在射击的时候,不但要给一把枪。还要给 一个弹夹才干射击
//子弹不能为负数
*/
#import<Foundation/Foundation.h>
#pragma mark -
#pragma mark Bullet类的声明
@interface Bullet : NSObject
{
@public
NSString *_size;
int _bulletCount;
}
@end
#pragma mark -
#pragma mark Bullet类的实现
@implementation Bullet
//Bullet类没有方法。所以没有类的实现部分,可是最好写上
@end
#pragma mark -
#pragma mark Gun类的声明
@interface Gun : NSObject
{
@public
NSString *_size;
}
-(void)shoot:(Bullet *)bullet;
@end
#pragma mark -
#pragma mark Gun类的实现
@implementation Gun
-(void)shoot:(Bullet *)bullet
//在shoot方法中。要射击必须有子弹,所以有一个子弹的參数,这里是否射击要取决于子弹是否不为0(有子弹才干射击)。所以里面有推断
{
if(bullet->_bulletCount>0)
{
bullet->_bulletCount--;
NSLog(@"tututututu.....\n还剩下%d颗子弹",bullet->_bulletCount);
}
else
{
NSLog(@"没子弹了~");
}
}
@end
#pragma mark -
#pragma mark Soldier类的声明
@interface Soldier : NSObject
{
@public
NSString *_name;
int _life;
int _level;
}
-(void)fireByGun:(Gun *)gun andBullet:(Bullet *)bullet;
//这种方法叫做用“大兵用枪开火射击”,所以说大兵开枪要用枪,然后抢里还得有子弹。所以自然这种方法有两个參数
@end
#pragma mark -
#pragma mark Soldier类的实现
@implementation Soldier
-(void)fireByGun:(Gun *)gun andBullet:(Bullet *)bullet
{
[gun shoot:bullet];
//这里子弹作为參数传递给shoot方法(这里是第二次子弹作为參数)
}
@end
#pragma mark -
#pragma mark main函数
int main()
{
@autoreleasepool {
Soldier *soldier1=[Soldier new];
soldier1->_name=@"Wang";
soldier1->_life=98;
soldier1->_life=2;
Gun *gun1=[Gun new];
gun1->_size=@"AK-47";
Bullet *bullet1=[Bullet new];
bullet1->_size=@"5.0口径";
bullet1->_bulletCount=4;
[soldier1 fireByGun:gun1 andBullet:bullet1];//大兵开枪这种方法。是第一次将子弹作为參数
[soldier1 fireByGun:gun1 andBullet:bullet1];
[soldier1 fireByGun:gun1 andBullet:bullet1];
[soldier1 fireByGun:gun1 andBullet:bullet1];
[soldier1 fireByGun:gun1 andBullet:bullet1];//一共4发子弹,那么打第五次(第五次运行这种方法。自然显示没子弹了)
}
return 0;
}
———————————————————————————————————————————
在使用类的过程中合理运用结构体
在使用类的过程中合理运用结构体能够节省非常多内存空间,比方说一个类的属性中,我们须要还有一个类的实例变量作为其属性(之前我们学习过),可是我们一定要再声明一个新类。占用的空间会非常多,比方说我们并不会用到的isa指针就得占8个字节。所以说,建立一个枚举类型的结构体就再好只是了,空间占有量小且不会被浪费。
以下一个小的练习题来介绍一下这个事情。
/*
设计一个”学生“类
1> 属性
* 姓名
* 生日(我们将生日这个參数设置为结构体类型,而不是单独将生日设置为类类型)
*/
#import <Foundation/Foundation.h>
//定义结构体的方法①:(我们为什么不用这样的方法呢。这是由于我们假设这样定义结构体。那么在定义结构体变量的时候就要每次都写上struct这个前缀,这样显得十分的麻烦,我们为了降低工作量能够依照以下的方法②进行定义)
//struct MyDate
//{
// int year;
// int month;
// int day;
//};
//定义结构体的方法②:(方法②有两个优点:第一我们定义了一个结构体,第二我们为这个结构体命名了一个新的名字“MyDate”,之后我们创建新的变量的时候能够直接用新名称“MyDate”去声明创建)
typedef struct
{
int year;
int month;
int day;
}MyDate;
@interface Student : NSObject
{
@public
NSString *_name;
MyDate _birthday;
}
@end
@implementation Student
@end
int main()
{
@autoreleasepool {
Student *stu1=[Student new];
stu1->_name=@"Wang";
//我们知道,为结构体变量初始化须要在声明的时候马上初始化,假设不马上初始化,系统是不认识的。就要一个一个參数的来初始化
//初始化结构体变量方法①:一个一个參数的来分步初始化
stu1->_birthday.year=1993;
stu1->_birthday.month=12;
stu1->_birthday.day=31;
Student *stu2=[Student new];
stu2->_name=@"Lao";
//初始化结构体变量方法②:强制类型转换(系统就明确初始化的是一个结构体变量。而不是一个一维数组什么的。这也就是为什么我们不能直接写成 stu2->_birthday={1993,6,14}; 由于这样写法系统不知道后面的是什么。后面的也可能是一个一维数组,可是前面的类型是确定的,是一个结构体类型)
stu2->_birthday=(MyDate){1993,6,14};
Student *stu3=[Student new];
MyDate md1={1993,1,1};
stu3->_name=@"wangwangwanglaolaolao";
stu3->_birthday=md1;
//初始化结构体变量方法③:先声明一个结构体变量md1,然后直接将md1赋给stu3->_birthday,这样类型就一致起来了
//输出验证一下正确性:
NSLog(@"\nstu1:\nname:%@,birthday:%d年%d月%d日",stu1->_name,stu1->_birthday.year,stu1->_birthday.month,stu1->_birthday.day);
NSLog(@"\nstu2:\nname:%@,birthday:%d年%d月%d日",stu2->_name,stu2->_birthday.year,stu2->_birthday.month,stu2->_birthday.day);
NSLog(@"\nstu3:\nname:%@,birthday:%d年%d月%d日",stu3->_name,stu3->_birthday.year,stu3->_birthday.month,stu3->_birthday.day);
}
return 0;
}
———————————————————————————————————————————
创建字符串的几种方法
//创建字符串的几种方法
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
//1、直接创建一个字符串(最普遍的方法,也是特殊的一种方法)
NSString *s = @"banzhang jiecao diaole "; //特殊使用方法
NSLog(@"%@",s);
//2、用类的思想去创建字符串(我们知道 NSString 是OC中字符串处理的类。那么用的类的思想应该这样创建)
NSString *s1 = [NSString new];
s1 =@"jian le ma";
NSLog(@"%@",s1);
//3、格式化创建字符串(依照指定的格式创建字符串)
// NSString *imgName = [NSString stringWithFormat:@"xxxxxx%02d.jpg",i];
// for (int i=0; i<10; i++) {
// NSString *imgName = [NSString stringWithFormat:@"xxxxxx%02d-%02d.jpg",i,i+1];
// NSLog(@"%@",imgName);
// }
//4、用一个已经存在的字符串创建一个新的字符串(也就是将s1中的值赋给新的字符串s2)
NSString *s2 = [[NSString alloc] initWithString:s1];
NSLog(@"s2 = %@",s2);
//提一句,事实上上面的new,stringWithFormat这些都是类方法。在系统中已经存在的方法。看到知道什么意思即可了
}
return 0;
}
———————————————————————————————————————————
OC字符串长度的计算方法
//OC字符串长度的计算方法(和C比較来介绍)
#import <Foundation/Foundation.h>
int main()
{
@autoreleasepool {
NSString *s1=@"王中尧";
//int len;//len来得到长度的值
//len = [s1 length]; // Implicit conversion loses integer precision: 'NSUInteger' (aka 'unsigned long') to 'int' 这句话我们会得到一个这种错误,事实上我们返回的是一个长整型的值给len,所以应该是unsigned long类型的,这个类型在此应写成NSUInteger(无符号的长整型,就是没有负数在里面)
NSUInteger len=[s1 length];
NSLog(@"\nlen:%ld",len);//len的值为3。说明汉字在oc字符串长度计算的时候也是占一个字节的,就把中文当作一个字符!
char *c1="王中尧";
printf("%ld",strlen(c1));//假设依照c语言的计算方式,中文是占3个字符。所以c1的长度是9
}
return 0;
}
———————————————————————————————————————————
OC多文件开发介绍
这里有两个类: Person 和 Dog
事实上就是将类的声明放在 Person.h 和 Dog.h 文件里。类的实现放在 Person.m 和 Dog.m 中,main.h 文件里面放程序的入口代码,另外主函数和类的实现文件里一定要使用 #import 包括对应的头文件。
.h .m 这两个文件要同名。
文件名称就是类名。
这是编程思想的一种体现,.h 和 .m 文件是全然独立的,这也是将 接口 和 实现 分离开来。
———————————————————————————————————————————
多文件开发的实现步骤
在这个OC_programproject下加入一个新的target
加入成功后,我们就拿一个样例来介绍一下 多文件开发的实现步骤。
我们能够右键这个target来创建类的头文件及类的源文件
显然。在这里我们要点击 New File… 标签
在这里我们能够直接点击 Cocoa Class 。这样输入类的名字后。类的 .h 文件和 .m 文件就都创建出来了(经经常使用的)。当然我们也能够去一个一个的创建。
显然。创建类的源文件(.m)就要去点击 Objective-C File 。而创建类的头文件(.h)就要去点击 Header File 了。
创建完毕之后要引入对应的文件。
比方在头文件里。肯定要加上 #import <Foundation/Foundation.h> ,而假设头文件里实用到别的类类型,那么也要引入别的类类型的头文件。而源文件一般就引入和自己同名的头文件就可以。
在main.m中也是用到什么文件就引入什么。
多引入也不会错,仅仅是多余。
一般我们都用 Cocoa Class 去创建类的源文件和类的头文件。创建完毕后自己主动生成里面对应的代码。比方头文件中面肯定包括 @interface @end…..我们仅仅需在已经给定我们的条条框框中加关键代码即可了。非常方便。
在下图中。我们还能够 New Group。来分门别类的存放我们的文件。这也是能够的(比方能够将一个类的头文件和源文件存在一个 Group 下)。非常清楚。
这一部分,大家在以后的学习过程中经经常使用。用这种方式简单,清晰。
要渐渐摒弃之前将大量代码写在一个文件里的陋习。
———————————————————————————————————————————
举报
- 本文已收录于下面专栏:
相关文章推荐
-
C++中的头文件和源文件:怎样写头文件
一、C++编译模式 通常,在一个C++程序中。仅仅包括两类文件——.cpp文件和.h文件。当中,.cpp文件被称作C++源文件。里面放的都是C++的源码;而.h文件则被称作C++头文件...- GUI1259802368
- 2017-04-01 20:32
- 305
-
文件映射对象读文件
普通的读文件耗时较长,文件映射读文件节约时间。读到后可发送大文件。// WriteFile.cpp : Defines the entry point for the console applicat...- a379039233
- 2016-03-09 16:44
- 303
-
java对象复制
利用apache commons-beanutils的开源实现。BeanUtils.copyProperties(dst, src)。方法可以将源对象和目标对象中同样名称的属性值复制过去。注意...
- qq_16465949
- 2014-08-13 18:13
- 200
-
文件映射对象写文件
能够写大文件。能够将网络传输的文件高速保存到当地磁盘中。// WriteFile.cpp : Defines the entry point for the console application. ...- a379039233
- 2016-03-09 16:33
- 355
-
将文件或目录封装成文件对象
package filetest;import java.io.File;public class FileDemo { public static void main(String[] arg...- taoxiuxia
- 2015-10-10 15:54
- 321
-
android将对象写入文件和从文件里读取对象数据
FileOutputStream fileOutputStream = null; ObjectOutputStream objectOutputStream = null; try{ JSON...- qq_29678299
- 2016-04-19 21:33
- 744
-
在项目中依据配置文件路径生成File对象的方法
1.怎样得到File对象 File类最经常使用的构造方法有两个,File(String pathname) 及File(URI uri) 。当中最最经常使用的构造方法是File(String pathname...- koushr
- 2016-02-15 15:52
- 1031
-
C++中的头文件和源文件:怎样写头文件
C++中的头文件和源文件 一、C++编译模式 通常,在一个C++程序中。仅仅包括两类文件——.cpp文件和.h文件。当中,.cpp文件被称作C++源文件,里面放的都是C++的源码;而.h文件则...- guoyong10721073
- 2014-05-07 21:31
- 23112
-
GitHub 上排名前 100 的 Objective-C 项目简单介绍
GitHub Top 100 简单介绍 主要对当前 GitHub 排名前 100 的项目做一个简单的简单介绍, 方便刚開始学习的人高速了解到当前 Objective-C 在 GitHub 的情况. Android ...- sunnyboy9
- 2016-03-24 23:31
- 557
-
Objective-C Runtime
Obj- 啸笑天
- 2014-12-06 18:31
- 25365
0条评论