Objective-C 学习笔记(Day 2)

———————————————————————————————————————————

如何根据题目准确完整清晰的声明一个类并实现给定的行为

/*

//下面这个程序教大家如何根据题目去声明一个类,并完成题目中描述的行为。如何让代码表示的准确清晰。

类名: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->[email protected]"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)函数不可以访问对象中的成员变量

这一部分纯理论知识,大家如果对里面的某些地方不懂,或者不信任,那么可以去简单的验证一下,也不麻烦~

———————————————————————————————————————————

常见错误的汇总

这一部分初学者常错,可以着重看看,这一部分很简单,主要是用心细心。

重点我已经用“★”标记,读者重点去看看。

1)★★@interface @end  和 @implementation @end 是不能嵌套的,不能把方法的实现关键字夹在声明的关键字中间

2)@end不要漏写

3)成员变量(属性),写在大括号里

4)★方法的声明 不要 写在大括号里

5)★★★声明的同时不要对成员变量初始化,这里怎么理解呢?那就是,成员变量(实例对象的具体属性)不能脱离对象而独立存在

6)★★方法无法和函数一样调用

7)★★★成员变量和方法不能用static等等关键字修饰,修饰他们一般用到的是public、protect这些关键字

8)★★★类的实现部分,也就是@implementation … @end关键字及其中间包含的方法实现部分,可以写在main函数的后面。但是@interface … @end关键字及其中间包含的类的声明部分,是必须写在main函数的前面的

9)★★如果有多个类,声明和实现部分顺序是可以打乱的,但是声明部分一定要在实现部分的前面

10)★★★★★最后一点,也是最最重要我要说明的。就是在应用@try @catch @finally语句中的时候,捕捉错误信息的代码是怎么写的。我们知道,@try关键字后面是写可能会出错的代码,@catch关键字后面是写出错之后我们需要处理执行的代码,@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->[email protected]"Wang";

p1->_sex=sMan;

Person *p2=[Person new];

p2->[email protected]"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;

}

———————————————————————————————————————————

对象作为对象方法的参数连续传递

//对象作为方法的参数连续传递,一个题来解释这个问题。说实话,这部分很简单,虽然题目啰嗦,但是就是说了一个事儿

//有两个方法,一个是士兵开枪,另外一个是枪射击子弹。士兵开枪需要用到子弹,然后还需要用到枪射击子弹这个方法,而枪射击子弹又要用到子弹,所以说子弹这个对象在两个方法中都用作参数传递了,所以叫对象作为方法的参数连续传递

//再缕一遍,第一个类的对象方法使用了第二个类和第三个类的实例对象作为参数,而在第一个类的对象方法体内让第二个类的实例对象去调用第二个类的对象方法,而第二个类的对象方法又同样使用了第三个类的实例对象作为参数。所以说,这么一个简单的程序,让第三个类的实例对象两次作为对象方法的参数出现,这也就是对象作为方法的参数连续传递

/*

士兵开枪 枪射击子弹

枪类:

名称: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->[email protected]"Wang";

soldier1->_life=98;

soldier1->_life=2;

Gun *gun1=[Gun new];

gun1->[email protected]"AK-47";

Bullet *bullet1=[Bullet new];

bullet1->[email protected]"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->[email protected]"Wang";

//我们知道,为结构体变量初始化需要在声明的时候立即初始化,如果不立即初始化,系统是不认识的。就要一个一个参数的来初始化

//初始化结构体变量方法①:一个一个参数的来分步初始化

stu1->_birthday.year=1993;

stu1->_birthday.month=12;

stu1->_birthday.day=31;

Student *stu2=[Student new];

stu2->[email protected]"Lao";

//初始化结构体变量方法②:强制类型转换(系统就明白初始化的是一个结构体变量,而不是一个一维数组什么的。这也就是为什么我们不能直接写成 stu2->_birthday={1993,6,14};  因为这样写法系统不知道后面的是什么,后面的也可能是一个一维数组,但是前面的类型是确定的,是一个结构体类型)

stu2->_birthday=(MyDate){1993,6,14};

Student *stu3=[Student new];

MyDate md1={1993,1,1};

stu3->[email protected]"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 [email protected]"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 *[email protected]"王中尧";

//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_program工程下添加一个新的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 下),很清楚。

这一部分,大家在以后的学习过程中经常用,用这样的方式简单,清晰。要渐渐摒弃之前将大量代码写在一个文件中的陋习。

———————————————————————————————————————————

声明:

作者按照黑马 如意大师 的教学视频学习,内容主要来自如意大师的视频讲解,另外在学习过程中查找了大量的辅助资料,综合完善了这部分的笔记内容。内容的概括一部分来自于如意大师的教学笔记,一部分来自于我自己的编排理解。无论是哪一部分,都是作者亲自手敲验证(包括代码和注释),没有一点是完全copy的。仅供作者本人翻看复习,当然喜欢的读者可以来看一下,绝对会对你的学习有帮助的。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-26 21:25:08

Objective-C 学习笔记(Day 2)的相关文章

Objective - C学习笔记:UIView的使用方法

1.1 - (void)layoutSubviews; * 当一个控件的frame发生改变的时候就会自动调用 * 一般在这里布局内部的子控件(设置子控件的frame) * 一定要调用super的layoutSubviews方法 1.2 - (void)didMoveToSuperview; * 当一个控件被添加到父控件中就会调用 1.3 - (void)willMoveToSuperview:(UIView *)newSuperview; * 当一个控件即将被添加到父控件中会调用 @interf

Objective - C 学习笔记:UIPickerView 和 UIDatePicker的基本使用

1.UIPickerView 1.1. UIPickerView的常见属性 // 数据源(用来告诉UIPickerView有多少列多少行) @property(nonatomic,assign) id<UIPickerViewDataSource> dataSource; // 代理(用来告诉UIPickerView每1列的每1行显示什么内容,监听UIPickerView的选择) @property(nonatomic,assign) id<UIPickerViewDelegate>

Objective - C 学习笔记:程序启动原理

1.Info.plist常见的设置 * 建立一个工程后,会在Supporting files文件夹下看到一个“工程名-Info.plist”的文件,该文件对工程做一些运行期的配置,非常重要,不能删除 * 在旧版本Xcode创建的工程中,这个配置文件的名字就叫“Info.plist” * 项目中其他Plist文件不能带有“Info”这个字眼,不然会被错认为是传说中非常重要的“Info.plist” * 项目中还有一个InfoPlist.strings的文件,跟Info.plist文件的本地化相关

objective - C学习笔记: tableView的刷新

1: 数据刷新的总体步骤 1.1: 修改模型数据 1.2: 刷新表格(刷新界面) 2: 刷新表格的方法 // 全局刷新(每一行都会重新刷新) - (void)reloadData; // 局部刷新(使用前提: 刷新前后, 模型数据的个数不变) - (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation; // 局部删除(使用前提: 模型数据减少的个

Objective - C学习笔记:控制器的管理

1. 如何创建一个控制器 1.1. 控制器常见的创建方式有以下几种 //1.1.1:通过storyboard创建 //1.1.2:直接创建 YHViewController *viewController = [[YHViewController alloc] init]; //1.1.3:指定xib文件来创建 YHViewController *viewController= [[YHViewController alloc] initWithNibName:@"YHViewControlle

Objective - C 学习笔记:消息机制的原理与使用

1.通知中心(NSNotificationCenter) 1.1.每一个应用程序都有一个通知中心(NSNotificationCenter*)实例,专门负责协助不同对象之间的消息通信 1.2.这就是观察者模式(Observer),任何一个对象都可以向通知中心发布通知(NSNotification*),描述自己在做什么.其他感兴趣的对象(Observer观察者)可以申请在某个特定通知发布时(或在某个特定的对象发布通知时)收到这个通知 2.通知(NSNotification) 2.1.一个完整的通知

Objective - C 学习笔记:程序启动的完整过程

1. main函数 2. UIApplicationMain * 创建UIApplication对象 * 创建UIApplication的delegate对象 3.1 delegate代理开始处理(监听)系统事件  (没有storyboard) * 程序启动完毕的时候, 就会调用代理的application:didFinishLaunchingWithOptions:方法 * 在application:didFinishLaunchingWithOptions:中创建UIWindow * 创建和

Objective - C 学习笔记:监听文本框TextField的文字改变

* 一个文本输入框的文字发生改变时,文本输入框会发出一个UITextFieldTextDidChangeNotification通知 * 因此通过监听通知来监听文本输入框的文字改变 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChange) name:UITextFieldTextDidChangeNotification object:textField]; // textField

ufldl学习笔记与编程作业:Convolutional Neural Network(卷积神经网络)

ufldl出了新教程,感觉比之前的好,从基础讲起,系统清晰,又有编程实践. 在deep learning高质量群里面听一些前辈说,不必深究其他机器学习的算法,可以直接来学dl. 于是最近就开始搞这个了,教程加上matlab编程,就是完美啊. 新教程的地址是:http://ufldl.stanford.edu/tutorial/ 本节学习地址:http://ufldl.stanford.edu/tutorial/supervised/ConvolutionalNeuralNetwork/ 一直没更

ufldl学习笔记与编程作业:Softmax Regression(vectorization加速)

ufldl出了新教程,感觉比之前的好,从基础讲起,系统清晰,又有编程实践. 在deep learning高质量群里面听一些前辈说,不必深究其他机器学习的算法,可以直接来学dl. 于是最近就开始搞这个了,教程加上matlab编程,就是完美啊. 新教程的地址是:http://ufldl.stanford.edu/tutorial/ 本节是对ufldl学习笔记与编程作业:Softmax Regression(softmax回归)版本的改进. 哈哈,把向量化的写法给写出来了,尼玛好快啊.只需要2分钟,2