Objective-C 学习笔记(Day 1)

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

Hello World



//引入头文件

//c中的引入头文件的方式

//#include <stdio.h>

//#include <Foundation/Foundation.h>

#import <Foundation/Foundation.h>  //引入头文件(单单引入这一个头文件,无后顾之忧,里面包含了太多的头文件,一有全有)



//1、面试题:为什么要使用import,import和include的区别

//include 和 import 都是引入头文件

//import引入的头文件,可以防止重复包含,什么是重复包含呢,简而言之,重复包涵就是多次包含相同的头文件,编译时间会大大增加,而对程序的最终结果危害不大。这也是import先进的地方,以后都用import吧

//include它是使用预处理指令防止重复包含,如果没有写预处理指令,则无法防止重复包含问题



//2、import 和 @class的区别



//3、Foundation/Foundation.h 是什么东西

//   1)头文件

//   2)头文件的位置

//   3)文件包含了其他的大量的头文件

//     /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/Foundation.framework/Headers/Foundation.h

//   作用:把Foundation.h引入了,等于把OC的库文件都引过来了



int main(int argc, const char * argv[]) {//小括号里面的东西可以省略,无参

    @autoreleasepool {//这里是一个自动释放池,现在先不涉及,以后内存管理的时候需要用到

        

        //strlen(<#const char *#>) 虽然没引入包含计算字符串长度方法的头文件,但是这只是表面现象,我们引入了<Foundation/foundation.h>之后就全有了!所以说其实我们已经引入了包含计算字符串长度方法的头文件了。

        // insert code here...

        //NSLog是一个函数,里面必须有@,@表示后面跟一个字符串,等价于printf函数,而且NSLog该大写的地方一定要大写

        //作用:向控制台输出字符串

        NSLog(@"Hello, world!");

    }

    return 0;

}





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

NSLog函数的使用



#import <Foundation/Foundation.h>



int main(int argc, const char * argv[]) {

    @autoreleasepool {

        // insert code here...

        //NSLog和printf使用的差异

        //1、NSLog 会自动换行  而printf不会自动换行

        //2、NSLog 会自动输出时间等项目信息,printf不会输出调试信息

        //3、NSLog 函数的参数是一个NSString 对象

        //         printf输出的是一个字符串常量指针

        NSLog(@"Hello, World!”);   //记住,一定要加@符号,因为@符号是要加在所有的字符串前面的。这表明了这个字符串是一个oc字符串,而不是c字符串

        printf("Hello, World!\n");

        

        //2、NSLog格式化输出的问题

        

#import <Foundation/foundation.h>

int main()

{

    char a='X';

    int b=19;

    float c=1.23;

    double d=3.566;

    printf("a=%c,b=%d,c=%.2f,d=%.2f\n",a,b,c,d);

    NSLog(@"a=%c,b=%d,c=%.2f,d=%.2f",a,b,c,d);//NSLog可以和printf一样输出,不同之处要再字符串格式的前面加一个@符号。也可以说明OC向下包容C

    char *ch="412sss王中尧4rfd";

    printf("%s\n",ch);

    NSLog(@"\n----->%s",ch);//该行无法正常输出。不能这么写的,在oc中有oc的格式(注意,这里是字符串,刚刚验证了一下,如果字符串中包含汉字字符,则整个字符串都无法正常输出,但是如果是只含一般的字母和数字,是可以正常输出的,这里注意一下。虽然这么说,但是总而言之,oc还是有自己固定的格式,所以还是用oc自己的方式去定义字符串和用oc的格式去输出字符串吧。)

    NSString *e=@“34gwerger43g王中尧”;//oc中声明并初始化一个字符串是和c不一样的,是NSString *abc=@“asdfasfa”;  一定要声明成字符串指针变量的形式哦!

    NSLog(@"%@",e);//%@即oc字符串的格式,oc中打印oc字符串的格式也是不同的

    

    //当然也不能用printf去打印e,因为NSString是oc独有的,C是不支持的。

    //如: printf("%@",e); 这条语句只能打印出一个@号,但是字符串e是打印不出来的

    //所以说,oc很傲娇,我们只能用oc的格式去打印oc的字符串等

    return 0;

}





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

@符 和 注释符 的使用



@符

1)@“ ”  

这样在@后面跟一个字符串,表示将C字符串转化为OC的字符串,这也是OC字符串特有的表示形式

2)@标识符   OC中大部分关键字都是以@开头的,比如@inferface,@end,@class



注释符

1)单行注释     //

2)多行注释     /*     */

3)文档注释     /**

          *     

          *

          */

文档注释可以在代码中提示这一部分的信息,挺好的。





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

访问OC源文件、C源文件中的函数



这一部分我们建立了一个oc program(包含main.m文件),和一个c文件(包括源文件和头文件)。接下来展示三个文件中的具体代码并讲解:

1)main.h文件



#import<Foundation/foundation.h>

#include "CC.h"

int main()

{

    void test();

    test();   //成功调用,显然,再oc中是可以访问c函数的

    ctest2();   //我们建立了一个c文件,然后再头文件(.h)中声明了一个函数,在源文件(.c)中实现声明了的方法。所以我们可以这样理解,要把方法声明写在头文件(.h)中,把方法定义写在源文件(.c)中.(刚刚测试了一下,将方法声明和定义都写在源文件(.c)中也是可行的。为什么可行呢,想一下,刚开始只学c的时候不就是新建项目就出现一个main.c么,开头还引入了stdio.h的头文件)。

       //解释一下c语言的源文件(.c)和c语言的头文件(.h):我们平常写的代码都是在源文件里,但是我们学习c的时候通常在这个源文件中将函数的声明和定义都包含了。在我们的源文件(.c)中由于需要对外提供接口,因此在源文件(.c)必须有一些函数或者是变量提供给外部其他文件进行调用。而头文件(.h),我们可以将他看成是一份接口描述文件,可以形象的理解成一份说明书,说明的内容就是我们的模块对外提供的接口函数或者是接口变量,同时也包含了一些宏定义和结构体信息,离开这些信息,很可能就无法正常使用接口函数和接口变量。总的来说,应该让外界知道的必须信息就应该出现在头文件(.h)里,不该让外界知道的信息就不应该出现在头文件(.h)里。这也就是模块化编程的概念。

    return 0;

}

void test()

{

    printf("1231\n");

}



2)CC.c



#include “CC.h"   

//使用<>这种方式,编译器查找的时候,会在编译器的安装目录的标准库中开始查找,””这种方式,会在当前的工程所在的文件夹开始寻找,也就是你的源程序所在的文件夹。所以说编译器中有的一般用< >,而自己写的头文件,一般用 “ ” 。

void ctest2()

{

    printf("This is a ctest2!!!");

}



3)CC.h



#include <stdio.h>

void ctest2();





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

C与OC的差异(1)



 OC 和 C对比学习

 

    1)  文件的差异:

    C中有  .c(源文件)  .o(目标文件)  .out(可执行文件)  .h(头文件)

    OC中有  .m(OC的源文件)  .h(头文件)  .mm(OC++的源文件)  前两个重点记忆

     这里再次强调一下,头文件中包含方法、属性的声明,源文件中包含类的实现文件,参与编译的文件,用来实现类中声明的方法。



    2)数据类型差异



     C中包括:基本类型(整型、字符型、实型)、构造类型(数组、结构体、共用体、枚举类型)、指针类型、空类型(void)、定义类型(typedef)



    OC中包括:基本数据类型(数值型(数值型、浮点型)、字符型、布尔型、空类型)、Block类型(有参数和返回值的代码块)、指针数据类型(类:class、id类型:在运行时才知道其中值类型是什么,编译的时候都不知道。也被形象的成为万能指针)、特殊类型(SEL、nil(对象为空))

    

   3)关键字差异



新增的关键字大部分有@标记,少数新增关键字需要特殊记忆一下,在此不列出了

 

   4)流程控制语句

 

       OC中并没有增加新的流程控制

 

       OC中提供一种增强型的for循环(唯一多了一个增强的for循环)

 

       NSArray *arr=@[@"one",@"two",@"three"];

 

       for(NSString *str in arr){

 

            NSLog(@"%@",str);

       

       }

 

   5)OC中函数的定义和声明的差异

     

      C语言中的函数

 

      int max(int x,int y);

      

      int max(int x,int y){

 

            return x>y?x:y;

      }

 

 

      OC中把 函数 称之为 方法  (这里必须注意!要称之为方法。下面怎么做的暂时不解释)

 

      +(void) test;

      -(void) test;

 

      -(int)max:(int)x andY:(int) y;

 

 

 */



下面的程序为大家展示了OC的增强for循环

#import <Foundation/Foundation.h>



int main(int argc, const char * argv[]) {

    @autoreleasepool {

       

        NSArray *arr=@[@"one",@"two",@"three"];

        //OC中的增强型for循环

        for(NSString *str in arr){

            

            NSLog(@"%@",str);

            

        }

   }

    return 0;

}



   

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

C与OC的差异(2)



/*

 

    1、新增的数据类型介绍

 

        Boolean用来存放逻辑值

 

        逻辑值: 真1          假0

 

        OC中也可以使用 true 表示真  false表示假

 

        用来存放true和false的结果的变量一般我们声明为 Boolean

 

    2、异常捕捉的方法

 

 */





#import <Foundation/Foundation.h>



int main(int argc, const char * argv[]) {

    @autoreleasepool {

        

        //1、Boolean类型的使用

        Boolean flag = true;

        //false 假  0

        flag = false;

        //true 真  1

        printf("flag = %d\n",flag);

        

        //用Boolean类型的变量经常用于条件判断

        if(flag){

        

            printf("xxxxxxx\n");

        

        }

        

        //2、存放逻辑值的另外一种方法

        //BOOL 它的取值 YES 和 NO

        //YES  真   1

        //NO   假   0

        BOOL flag2 = YES;//这里一定要注意BOOL是大写(下面是在网上精简的资料,但是还是不是太明确这个概念,还得慢慢琢磨)

        

        /*  bool只有一个字节。bool取值false和true,是0和1的区别; false可以代表0,但true有很多种,并非只有1,是剩余所有非0的值。 也就是说你定义一个bool型的变量,他的值非零,那么输出这个bool型的变量,结果就是1,反之同理。

         

            BOOL视环境而定,一般是4个字节,BOOL是微软定义的typedef int BOOL(在windef.h中)。与bool不同,它是一个三值逻

            辑,TRUE/FALSE/ERROR,返回值为大于0的整数时为TRUE,返回值为0时候,为FALSE,返回值为-1时为ERROR。

        */

        

        printf("YES   = %d\n",YES);

        printf("flag2 = %d\n",flag2);  // 1

        

        flag2 = NO;  //0

        

        //flag2 == YES

        if (flag2) {

            printf("0000000000\n");

        }

        

        // 1/0

        int a = 1;

        int b  = 1;

        

        b = NO;

        

        

        //注意:try catch 并不能检测所有的错误

        //先了解!

        

        @try {

            //此处放的事有可能出错的代码

            int result = a/b;

        }

        @catch (NSException *exception) {

            //此处放出错以后 我们处理的代码

            

        }

        @finally {

            //不管出没出错,这里的代码一定会执行

            printf("fengjie!\n");

        }

    }

    return 0;

}





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

面向对象编程的概念



面向过程:做一件事需要哪些步骤。关注的是解决问题的步骤。

面向对象:做一件事我需要哪些对象帮我去做,建立许多模型,来帮助我们完成。关注的是解决这个问题需要哪些具备相应功能对象。(当然面向对象是基于面向过程的,每一个对象的模块里面还是存在许多操作步骤的)



例子:

洗衣服这件事我们从面向对象和面向过程两个角度去分析:

面向过程:1、打开洗衣机 2、放进去衣服和洗衣粉 3、按下开关开始洗 4、洗完了之后拿出来晾起来

面向对象:1、找个女朋友 2、让女朋友去洗





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

类和对象



类是具有 相似内部状态(属性) 和 运动规律(行为) 的实体的集合(一种统称,或者是一种抽象)

类的内部状态是指类的集合中所有对象 共同的 状态,类的运动规律是指类的集合中对象 共同的 运动规律 。



比如说,有一个学生类:

年龄 班级 姓名 性别 —————— 类的属性

写作业 回答问题 考试 —————— 类的行为(方法)

张三 李四 —————— 类的对象



类的对象也就是将类实例化了。



我们可以联系到以前学过的结构体,很相似,但是不是一回事。比如类的属性就可以看成结构体的成员变量,但是结构体是不定义方法的。





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

类的声明和实现



/*



1> 方法的声明和实现,都必须以 + 或者 - 开头



    +  表示 类方法(静态方法)

    -   表示 对象方法(动态方法)



2> 在.h中声明的所有方法作用域都是public类型,不能更改

 

 */



#import <Foundation/Foundation.h>

//类的声明

@interface Car:NSObject //@inerface 类名:父类名      这个地方后面的父类名为NSObject,这个暂时先这么固定写法

{

    //类的属性在这里定义

    int lunzi;

    NSString *color;//用oc的方法定义字符串

    int speed;

}

    //类的行为(方法)在这里声明,暂时不写。

@end



//类的实现

@implementation Car

{

    //code(行为(方法)的具体实现)

}

@end



int main()

{

    @autoreleasepool {

       

    }

    return 0;

}





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

创建一个对象并访问成员变量(属性)



成员变量的常用 作用域 有3种:



1> @public 全局都可以访问

2> @protected 只能在类内部和子类中访问

3> @private 只能在类内部访问



代码:



#import <Foundation/Foundation.h>



@interface Car : NSObject

{

@public;//这个地方让属性变成全局的,这样就都能访问了,否则

    NSString *name;

    int lunzi;

    int speed;

    NSString *color;

}

//方法声明在这里(@interface和@end之间,且在大括号之外。如果没有属性,也就没有大括号,属性是可以没有的)

@end



@implementation Car

{

//行为(方法)的具体描述

}

@end



int main()

{

    @autoreleasepool

    {

        Car *car=[Car new];//这里在编写代码的时候,为了规范,我们可以先写[Car new],再写前面的部分,也看起来很专业。

        //★★★另外注意:所有OC对象都是用指针变量来接收的,如果你不了解指针,你记住下面这点就行了:利用类名定义一个变量时,类名后面一定要带个*号。★★★

        

        //OC中对象创建

        

        //[Car new];

        //做了3件事情

        // 1)向计算机申请内存空间

        // 2) 给类中的每一个成员初始化值

        // 3)返回新申请的空间的首地址

        

        //理解方式一:

        //定义了一个Car类型的指针变量

        //指针变量指向新申请的内存空间

        

        //理解方式二:(这是我们以后常用的理解方式)

        //用Car类实例化了一个实例对象car

        

        car->name=@"shifeng";//为我们实例化的对象属性赋值时,记得用 -> ,用 . 来访问会出错

        car->lunzi=3;

        car->speed=120;

        car->color=@"blue";

        

        NSLog(@"name:%@,lunzi:%d,speed:%d,color:%@",car->name,car->lunzi,car->speed,car->color);

        //当然输出的时候也要用->来调用!!!

    }

    return 0;

}





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

无参方法的声明、实现和调用



#import <Foundation/Foundation.h>



@interface Car:NSObject

{

    

@public;

    NSString *name;

    int speed;

    NSString *color;

    

}



-(void)run;//这是声明了两个无参无返回值的函数

-(void)stop;



@end



@implementation Car //这里记住下面是不用大括号将两个方法的实现括起来的,只有属性的定义需要括起来(@interface的下面属性部分),关键字@end其实起了一个大括号的作用了



-(void)run //动态方法,也就是成员方法

{

    NSLog(@"123");

}

-(void)stop

{

    NSLog(@"456");

}



@end



int main()

{

    @autoreleasepool {

        Car *car=[Car new];

        car->name=@"shifeng";

        car->speed=@"120";

        car->color=@"blue";

        NSLog(@"name:%@\nspeed:%d\ncolor:%@",car->name,car->speed,car->color);

        //调用方法。调用格式为:    [对象名 类方法名];

        [car run];

        [car stop];

        

    }

    return 0;

}





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

有参方法的声明、实现和调用



下面是一个计算器的类,用来简要说明这一部分的知识:



#import <Foundation/Foundation.h>



@interface Caculator : NSObject

{

    @public   //不一定要加冒号

    int _num1; //类中的属性,记得要用下划线加属性名的格式,标准格式

    int _num2;

}



// -(返回值类型)方法名1:(参数类型) 参数名;   //有一个参数的方法

// -(返回值类型)方法名1:(参数类型1) 参数名1  and:(参数类型2) 参数名2;   //有2个参数的方法



// -(int)sum:(int) x and:(int) y;  //方法的声明



// 有参方法的使用注意:

// 方法的类型   -  对象方法(动态方法)

// 方法的返回值类型: int 类型

// 方法的参数是: x   y

// 参数的类型: 第一个 int  第二个 int

// 方法名:  sum:   and:  (冒号是方法名的一部分)





-(int)sum;//声明了一个无参函数sum

-(int)sum:(int) x andaaa:(int) y;//有两个参数的函数 sum:  and:(这里的函数名是 sum: and: 所以说不和上面的无参函数重名)



@end



@implementation Caculator



-(int)sum //无参,有返回值的方法

{

    return _num1+_num2;

}



-(int)sum:(int) x and:(int) y and:(int) z //有参,有返回值的方法,每多一个参数,就多加一个 and:

{

    return x+y+z;

}

@end



int main()

{

    @autoreleasepool

    {

        Caculator *a=[Caculator new];//还是注意创建类的实力对象的时候,一定要是指针类型。有一个小技巧,在后面写[Caculator new] 的时候,可以先写里面的,然后再写后面半个中括号‘]’ ,这样前半个中括号也自动生成,很方便。

        

        //对象访问实例变量

        a->_num1=12;

        a->_num2=13;

        

        //调用无参方法

        int s1=[a sum];

        

        //调用有参方法

        int s2=[a sum:13 and:14 and:15];

        NSLog(@"%d,%d",s1,s2);

    }

    return 0;

}



下面是一个iPhone的类,加深这部分知识的理解:



/*

 类名:苹果手机(iPhone)

 属性:颜色(_color ), 大小(_size), _cpu

 行为:查看本机信息(aboutMyPhone),打电话(call), 发短信(sendMessage)

 

 实现该类,并:

 1)查看本机信息

 2)打电话给10086

 3)给10086发短信问联通的客服电话是多少

 

 */



#import<Foundation/Foundation.h>

typedef enum {kColorWhite,kColorBlack,kColorTHJ} iColor;  //定义一个枚举类型,用于声明一组命名了的常数,所以要用%d输出。这样解释就明白了把~

//typedef enum { 枚举成员 } 枚举名称;



@interface iPhone : NSObject

{

    @public

    iColor _color;  //将颜色这个属性声明为枚举类型,比设置成字符串类型更规范,可读性更高。

    float _size;

    NSString *_cpu;  //字符串类型的属性,要定义成字符串类型的指针变量

}



//方法的声明

-(void)about_My_iPhone;  //无参无返回值的方法,用来查看本机信息

-(void)calltelephone:(NSString *) telNum;  //有一个参数telNum(字符串类型)无返回值的方法,用来打电话

-(void)setMessage:(NSString *) telNum and:(NSString *) content;  //有两个参数telNum、content(内容的意思),用来给某某发短信

@end



@implementation iPhone



-(void)about_My_iPhone  //无参无返回值的方法,用来查看本机信息

{

    NSLog(@"Color:%d,Size:%.2f,Cpu:%@",_color,_size,_cpu);  //输出字符串属性值的时候,并不用加*号,直接用属性的名字即可( _cpu )。输出枚举类型的时候用的是%d,这里要切记!

}



-(void)calltelephone:(NSString *) telNum  //有一个参数telNum(字符串类型)无返回值的方法,用来打电话

{

    NSLog(@"call %@ by iPhone",telNum);

}



-(void)setMessage:(NSString *) telNum and:(NSString *) content  //有两个参数telNum、content(内容的意思),用来给某某发短信

{

    NSLog(@"set %@ to %@",content,telNum);

}



@end



int main()

{

    @autoreleasepool {

        iPhone *abc=[iPhone new];  //一定一定要注意,实例化类的对象的时候一定要实例化成指针变量的类型!!!切记!!!

        abc->_color=kColorWhite;

        abc->_cpu=@"ahagargrax";

        abc->_size=9.9;

        [abc about_My_iPhone];

        [abc calltelephone:@"10086"];  //字符串实参记得加@“”,这一点不要忘记!!!

        [abc setMessage:@"10086" and:@"i love you"];

    }

    return 0;

}





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

声明:

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

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

上一篇:rsyslog 日志统一搜集&message格式


下一篇:pod优先级与抢占测试