• 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! ");
            
            //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 ",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 ",ch);
        NSLog(@" ----->%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 ");
    }

    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 ",flag);
            
            //用Boolean类型的变量经常用于条件判断
            if(flag){
            
                printf("xxxxxxx ");
            
            }
            
            //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 ",YES);
            printf("flag2 = %d ",flag2);  // 1
            
            flag2 = NO;  //0
            
            //flag2 == YES
            if (flag2) {
                printf("0000000000 ");
            }
            
            // 1/0
            int a = 1;
            int b  = 1;
            
            b = NO;
            
            
            //注意:try catch 并不能检测所有的错误
            //先了解!
            
            @try {
                //此处放的事有可能出错的代码
                int result = a/b;
            }
            @catch (NSException *exception) {
                //此处放出错以后 我们处理的代码
                
            }
            @finally {
                //不管出没出错,这里的代码一定会执行
                printf("fengjie! ");
            }
        }
        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:%@ speed:%d color:%@",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的。仅供作者本人翻看复习,当然喜欢的读者可以来看一下,绝对会对你的学习有帮助的。

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

  • 相关阅读:
    Qt -- 鼠标移入移出事件 enterEvent、leaveEvent
    QT -- QPainter介绍
    Qt -- 浅析QFontMetrics 获取字体宽度,高度
    函数声明后面的const用法
    QT -- 读取file数据/写数据到file
    QT -- QLineEdit按下回车键获取信息
    C++ -- fgets,fputs,fputc,fgetc总结
    QT -- QString / std::string转换为const char*
    C++ -- fopen函数用法
    HTML DOM树
  • 原文地址:https://www.cnblogs.com/wzy294250051/p/4787901.html
Copyright © 2020-2023  润新知