文档章节

黑马程序员-8-Objective-C学习笔记(OC特有语法)

 明天过后1
发布于 2014/10/03 08:18
字数 2334
阅读 55
收藏 0

---------------------- Java培训.Net培训Android培训IOS培训、期待与您交流! ---------------------- 

1. Category

    a. 简介

        (1) 在不改变原来类模型的前提下,给类扩充一些方法 : a. 继承           b. Category

        (2) 继承 和 Category 区别 : 

            1) 使用思想不同,继承是子类在父类的基础之上拓展功能,子类与父类的逻辑关系明显,Category多用于团队分模块开发,在现有基础之上增加新功能。

            2) Category 不能修改成员变量的数目,而继承中子类可以增加成员变量的数目

            3) Category重写原生方法后可能会导致原生方法无法访问,而继承重写父类方法仍然可以访问父类的方法。

    b. 简单使用            

    // Person.h
    #import <Foundation/Foundation.h>
    @interface Person : NSObject
    - (void) test();
    @end
    
    // Person.m
    #import "Person.h"
    @implementation Person
    - (void) test
    {
        NSLog(@"test...");
    }
    @end  
    
    // Person+Person1.h
    #import "Person.h"
    @interface Person (Person1)
    - (void) test1();
    @end
    
    // Person+Person1.m
    #import "Person+Person1.h"
    @implementation Person (Person1)
    - (void) test1
    {
        NSLog(@"test1...");
    }
    @end  
    
    // main.m
    #import "Person.h"
    #import "Person+Person1.h"
    
    int main(){
        Person *p = [[Person alloc] init];
        // 优先去分类中查找,然后再去原来类中找,最后再去父类中找
        [p test]; // test...
        [p test1]; // test1...
        return 0;
    }

    c. 总结

                (1) Category 好处是一个庞大的类可以分模块来开发,更利于团队开发

                (2) 类对象调用方法的时候优先去分类中查找,然后再去原来类中找,最后再去父类中找

                (3) 不建议覆盖原有的方法,因为会导致源有方法无法使用。

                (4) 覆盖后该使用哪个方法决定于编译的优先级,查看编译的优先级:build phases->compile sources查看优先级,分类之间同名方法的优先级取决与分类的.m文件编译的顺序,比较靠后的优先级比较高


2. NSLog输出补充

    a. 预处理宏符号

关键字 NSLog中的占位符 描述
__func__ %s 当前方法签名
__LINE__ %d 此代码在源文件中的第几行
__FILE %s 该源文件的全路径
__PRETTY_FUNCTION__
%s 功能跟 __func__ 一样,不过此符号用于C++源文件中

    b. 如何获得常用的输出字符串

表达式 占位符 描述
NSStringFromSelector(__cmd) %@ 当前方法签名字符串
NSStringFromClass([self class]) %@ 当前类名字符串
[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] %@ 当前源文件的名字字符串
[NSThread callStackSymbols] %@ 获得程序运行时栈的可读设置数组,只适用于调试


3. SEL

    a. SEL类型的定义

            OC提供了一种新类型数据对类方法进行操作,源码中的原生定义如下:

                typedef struct objc_selector *SEL;

    a. 类方法存储位置

             对象调用方法都是通过isa指针去类对象中寻找,因此对象方法存储的位置是类对象中 : 

                 (1) 每个类的方法列表都存储在类对象中

                 (2) 每个方法都有一个与之对应的SEL类型的对象

                 (3) 根据一个SEL对象就可以找到方法的地址,进而调用方法

    c. SEL对象的创建

    SEL s = @selector(test);
    SEL s2 = NSSelectorFromString(@"test");


4. @property

        @property是编译器特性,它可以帮助我们自动生成一些代码,其中包括可以自动生成成员变量,自动生成成员变量的setter 和 getter.

    a. @property会生成什么代码   

        (1) @property 如果不加任何参数会根据情况生成 属性 和 普通的 setter,getter

            1) 如果已经定义了要生成的属性(默认私有),那么编译器不会去定义

            2) 如果已经声明了或者定义了要生成 setter 和 getter 将不会去 声明 和 定义

            3) 生成的代码取决于 @property 后面的变量名

    #import <Foundation/Foundation.h>

    @interface Cat : NSObject
    // @property自动生成如下代码
    /*
    {
        @private
        int _age;
    }
    -(void) setAge:(int)age;
    - (int) age;
    */
    // 注意 : 生成的属性名称是在前面加上一条下划线 : _age
    @property int age;
    @end
    
    @implementation Cat
    // @property自动生成如下代码
    /* 普通的setter 和 getter
    -(void) setAge:(int)age
    {
        _age = age;
    }
    - (int) age
    {
        return _age;
    }
    */
    @end

    b. @property 的参数以及作用

            (1) set方法内存管理相关参数:

                 retain: release旧值,retain新值

                 assign: 直接赋值 (缺损值)

                 copy: 释放旧值,copy新值,此属性只对那些实行了NSCopying协议的对象类型有效

    // retain
    @property (retain) NSString *name;
    /* 生成代码
    - (void) setName:(NSString *)name
    {
        if ( _name != name ){
            [_name release];
            _name = [name retain];
        }
    }
    */
    
    // assign
    @property (assign) NSString *name;
    /* 生成代码
    - (void) setName:(NSString *)name
    {
        _name = name;
    }
    */
    
    // copy
    @property (copy) NSString *name;
    /* 生成代码
    - (void) setName:(NSString *)name
    {
        if ( _name != name ){
            [_name release];
            _name = [name copy];
        }
    }
    */


             (2) set方法是否生成:

                 readonly: 只生成get方法。

                 readwrite: set方法和get方法都生成(缺损值)

             (3) 多线程管理:

                 noatomic: 性能高,但线程不安全

                 atomic: 性能低,但线程安全

             (4) set方法和get方法的方法名字:

                 setter : 决定了set方法的名称,一定要有个冒号 :

                 getter : 决定了get方法的名称(一般用在BOOL类型)

        // setter
        @property (setter = setNewAge:) int age;
        /* 生成代码
        - (void) setNewAge:(int)age
        {
            _age = age;
        }
        */
        
        // getter 
        @property (getter = isOk:) BOOL ok;
        /* 生成代码
         - (BOOL) isOk
         {
             return _ok;
         }
        */

    c. 使用注意

        (1) 通常情况下为了性能高一般会加上 noatomic 参数

        (2) 对于基本数据类型使用 assign OC对象类型使用 retain

        (3) 为了提高可读性建议加上 readwrite 或者 readonly 参数

    // 基本数据类型
    @property (noatomic,readwrite,assign) int age;
    
    // OC对象类型
    @property (noatomic,readwrite,retain) NSString *name;


5. block

    a. 简介

            代码块本质上和变量类似。不同的是,代码块存储的数据是一个函数体。使用代码块是,你可以像调用其他标准函数一样,传入参数数,并得到返回值。

             block的声明与函数指针声明很像,不过block有它特有的标志(^),如下图 :

                    

    b. 简单使用

    #import <Foundation/Foundation.h>
    
    int main(){
        void (^print)(NSString *str);
        print = ^(NSString *str){
            NSLog(str);
        };
        print(@"hello world");
        return 0;
    }

    c. block的递归调用

    #import <Foundation/Foundation.h>
    // 注意递归调用block前要把block的函数体定义出来
    int main(){
        int (^accumulate)(int) = ^(int a){
            int sum = a;
            if ( a > 0 ){
                a--;
                sum += accumulate( a-- );
            } else {
                return sum;
            }
        };
        NSLog(@"accumulate 5 = %d",accumulate(5));
        return 0;
    }

    d. block访问外部变量

    #import <Foundation/Foundation.h>
    /*
        block代码块访问block之外的变量如果不加任何处理编译会报错
        因此如果block要访问外部变量,请给变量加上__block关键字
    */
    // 这里结合typedef使用block
    typedef int (^MyBlock)(int);
    int main(){
        __block int a = 10;
        MyBlock addWithA;            // block的声明
        addWithA= ^(int b){
            b += a;
            return b;
        };
        int result = addWithA(10);
        NSLog(@"a + b = %d",result);
        return 0;
    }


6. @protocol

    a. 简介

            (1) @protocol,简称协议,主要是用来方便程序员之间交流的一种OC特性,它与java中的接口相似,它的组成是 @protocol + 方法列表 + @end;

           (2) 它的结构和使用模板如下 : 

         1.协议的定义        
             @protocol 协议名称 <NSObject>
              @required
              // 方法声明列表....
              @optiuonal
              // 方法声明列表
             @end
         
         
         2.如何遵守协议
             1> 类遵守协议
             @interface 类名 : 父类名 <协议名称1, 协议名称2>
             @end
         
             2> 协议遵守协议
             @protocol 协议名称 <其他协议名称1, 其他协议名称2>
             @end

            (3) 协议提供两个关键字用来限定方法是否强制实现 : 

                1) @required (默认),强制实现,如果不实现会报警告.由于OC是弱语法,因此如果类没有实现required方法编译也不会报错

                2) @optional , 可以不实现,如果不实现也不会包警告

    b. 使用

            (1) 对于协议的定可以放在其他文件中 也可以单独新建文件存放,一般建议会单独新建文件存放

            (2) 如果要求类要遵守某个协议,那么必须让这个协议遵守<NSObject>协议,否则该类的实例会失去NSOject的某些方法。

            (3) 协议也可以对类的成员变量进行限定

    // 以下代码暂时不考虑内存管理
    /*------------------------------------------- ClassProtocol.h -------------------------------------------*/
    #import <Foundation/Foundation.h>
    @protocol ClassProtocol <NSObject>
    
    @required
    - (void) test; 
    
    @optional
    - (void) test1;
    
    @end
    
    /************************************************************************************************************/
    
    /*------------------------------------------- PropertyProtocol.h -------------------------------------------*/
    #import <Foundation/Foundation.h>
    @protocol ClassProtocol <PropertyProtocol>
    
    - (void) test2;
    
    @end
    /************************************************************************************************************/
    
    /*------------------------------------------- Dog.h -------------------------------------------*/
    #import <Foundation/Foundation.h>
    @protocol PropertyProtocol <NSObject>
    
    @interface Dog: NSObject <PropertyProtocol>
    
    @end
    /************************************************************************************************************/
    
    /*------------------------------------------- Dog.m -------------------------------------------*/
    #import "Dog.h"
    #import "PropertyProtocol.h"
    
    @implementation Dog
    
    - (void) test2
    {
        NSLog(@"PropertyProtocol  default required -- test2");                        // 实现 PropertyProtocol的 默认 required 方法    
    }
    
    @end
    /************************************************************************************************************/
    
    /*------------------------------------------- Person.h -------------------------------------------*/
    #import <Foundation/Foundation.h>
    #import "Dog.h"
    
    @protocol ClassProtocol                                    // 告诉编译器,Test是一个协议,在使用该协议具体定义的函数时候才把该协议文件import进来,提高编译效率
    @protocol PropertyProtocol
    
    @interface Person : NSObject <ClassProtocol>
    
    @property (nonatomic,retain) Dog<PropertyProtocol> *dog; // 协议对成员变量限定   
    // @property (nonatomic,retain) id<PropertyProtocol> *dog;  //等价于上一句,不过可能会失去Dog特有的方法
    
    @end
    /************************************************************************************************************/
    
    /*------------------------------------------- Person.m -------------------------------------------*/
    
    #import "Person.h"
    #import "ClassProtocol.h"
    
    @implementation Person
    
    - (void) test
    {
        NSLog(@"ClassProtocol required -- test");                        // 实现 ClassProtocol 的 required 方法    
    }
    
    
    - (void) test1
    {
        NSLog(@"ClassProtocol optional -- test1");                        // 实现 ClassProtocol 的 optional 方法    
    }
    
    @end
    /************************************************************************************************************/
    
    
    /*------------------------------------------- main.m -------------------------------------------*/
    
    #import "Person.h"
    #import "Dog.h"
    
    #import "ClassProtocol.h"
    #import "PropertyProtocol.h"
    
    int main{
        Person<ClassProtocol> *p = [[Person alloc] init];                  // 显式实例化一个遵守 ClassProtocol 的Person对象
        // id<ClassProtocol> *p = [[Person alloc] init];                   // 显式实例化一个遵守 ClassProtocol 的 OC 对象,该对象只保留了 ClassProtocol 里面的方法,失去了Person特有的方法
        Dog *dog = [[Dog alloc] init];                                     // 实例化一个遵守 PropertyProtocol 的Dog对象
        [dog test2];                                                       // 调用实现协议的方法
        
        [p setDog:dog];                                                    // 对协议限定的成员变量赋值,如果dog变量不遵守 PropertyProtocol 编译会报错
        
        [p test];
        [p test1];
        return 0;
    }
    
    /************************************************************************************************************/



---------------------- Java培训.Net培训Android培训IOS培训、期待与您交流! ---------------------- 

 详情请查看:http://edu.csdn.net/heima



© 著作权归作者所有

共有 人打赏支持
粉丝 2
博文 23
码字总数 36166
作品 0
佛山
一、Objective-C概述

说明:这个Objective-C专题,是学习iOS开发的前奏,也为了让有面向对象语言开发经验的程序员,能够快速上手Objective-C。如果你还没有编程经验,或者对Objective-C、iOS开发不感兴趣,请忽略...

长平狐
2013/03/28
113
0
一、C语言概述

说明:这个C语言专题,是学习iOS开发的前奏。也为了让有面向对象语言开发经验的程序员,能够快速上手C语言。如果你还没有编程经验,或者对C语言、iOS开发不感兴趣,请忽略 为什么iOS开发要先...

长平狐
2013/03/28
109
1
Objecitive-C中的nil

当我学习OC的时候,我总是忍不住在对比。Actionscript是如何实现,而oc又是如何实现。这不,碰到nil的时候我发现了很大的不同之处。做个笔记。 在as中,如果将一个对象置为null,相当于空指针...

ChildhoodAndy
2013/03/21
0
3
学习笔记整理

写iOS 程序的时候往往需要很多第三方框架的支持,可以大大减少工作量,讲重点放在软件本身的逻辑实现上。 GitHub 里面有大量优秀的第三方框架,而且 License 对商业很友好。一下摘录一下几乎...

我是IT码农
2016/03/29
8
0
15个快速学习苹果Swift编程语言的入门教程

要说今年最火的编程语言是什么。那就非Swift莫属了。当然最主要还是市场炒的比较热,加上官方Swift教程《The Swift Programming Language》在北航的大三学生发起在github上进行协同翻译获得了...

欲思
2014/07/24
19.5K
7

没有更多内容

加载失败,请刷新页面

加载更多

下一页

JS三元运算示例

1. topFlag=topFlag ==0?1:0; 等于 if(topFlag=00){ topFlag=1; }else if(topFlag == 1){ topFlag=0; } 2. 5>3?alert('5大'):alert('3大'); 即 if(5>3){alert('5大')}else{alert('3大')}; 注......

森火
58分钟前
0
0
利用Slf4j的MDC跟踪方法调用链

why? 一个web项目通常提供很多URL访问地址, 项目一般都是分层处理,例如Controller——>Service——>DAO。 如果想根据日志查看用户一次请求都走了哪些方法(多数是查错误)。 如果系统是多人...

杨春炼
今天
6
0
Maven介绍及安装

Maven介绍及安装 以下内容是本人早期学习时的笔记,可能比较详实繁琐,现在复习一下Maven,顺便将内容抛出来,供大家一起学习进步。 一、Maven简介 Maven是Apache旗下的一款项目管理工具,是...

星汉
今天
0
0
小程序Aes解密

主要步骤: 1、下载AES源码(JS版) 2、在小程序中新建一个公共的文件夹,把AES源码拷贝进去(注意:需要暴露接口 module.exports = CryptoJS;) 3、添加一个用于加密解密的公共JS,可取名为...

Mr_Tea伯奕
今天
0
0
Go实现文件传输(基本传输可用)

发送端 package mainimport ("fmt""os""net""io")func SendFile(path string, connect net.Conn){file, oerr :=os.Open(path)if oerr !=nil{fmt.Println("Open", oerr)......

CHONGCHEN
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部