• RunTime运行时、Xcode编译流程


     

    OC程序开发过程

    #import预处理指令有两个作用:(1)与#include一样,拷贝文件内容(2)可以自动防止文件的内容被重复拷贝

    程序编译连接过程:

     源文件(.m)---(编译)---->目标文件(.0)-----(链接)---->可执行文件(.out)

    Foundation框架。如果要使用框架中的所有头文件那么应该怎么办?包含框架的主头文件。主头文件是一个框架中最主要的头文件,每个框架的主头文件名和框架名一致。

    如#import<foundation/foundation.h>

     运行过程如下:

     (1)编写OC源文件  .m .c

    (2)编译文件  cc -c xx.m  xxx.c

    (3)链接  cc xx.o xxx.o  -framework Foundation

    (4)运行 ./a.out

     文件编译

    在工作中,通常把不同的类放到不同的文件中,每个类的声明和实现分开,声明写在.h头文件中,实现写在相应的.m文件中去,类名是什么,文件名的前缀就是什么。

    假设有两个类,分别是Person类和Dog类,则通常有下面五个文件:

    (1)Person.h    Person类的声明文件

    (2)Person.m    Person类的实现文件

    (3)Dog.h Dog类的声明文件

    (4)Dog.m Dog类的实现文件

    (5)Main.m 主函数(程序入口)

    在主函数以及类的实现文件中要使用#import包含相应的头文件。

    补充:import有两个作用:一是和include一样,完完全全的拷贝文件的内容;二是可以自动防止文件内容的重复拷贝(即使文件被多次包含,也只拷贝一份)。

    在使用命令行进行编译链接文件的时候,通常是把.m文件单文件编译,然后再把所有的目标文件链接,但是在Xcode中,是把所有的.m文件都进行编译链接的,如果出现重复定义的错误,那大部分问题根源应该就是文件内容被重复包含或者是包含.m文件所引起的。

    源文件中不论是使用include还是import,都不能包含.m或者是.c文件,只能放声明。因此,在OC中通常把类拆分开来,拆分成声明和实现两个部分。

    提示:这也是编程思想的一种体现,可以说.h和.m文件时完全独立的,只是为了要求有较好的可读性,才要求两个文件的文件名一致,这也是把接口和实现分离,让调用者不必去关心具体的实现细节。

    Xcode是写一行编译一行,有简单的修复功能,红色是错误提示,黄色警告。如果在程序中声明了一个变量,但是这个变量没有被使用也会产生警告信息。在调试程序的时候,如果发现整个页面都没有报错,但是一运行就错误,那么一定是链接报错。

    RunTime运行时

    runtime实现的机制是什么,怎么用,一般用于干嘛? 这个问题我就不跟大家绕弯子了,直接告诉大家, runtime是一套比较底层的纯C语言API, 属于1个C语言库, 包含了很多底层的C语言API。在我们平时编写的OC代码中, 程序运行过程时, 其实最终都是转成了runtime的C语言代码, runtime算是OC的幕后工作者 比如说,下面一个创建对象的方法中, 举例: OC : [[MJPerson alloc] init] runtime : objc_msgSend(objc_msgSend("MJPerson" , "alloc"), "init")

    NSObject

    @interface NSObject <NSObject> {

        Class isa  OBJC_ISA_AVAILABILITY;//class

    }

    NSObject 只有一个成员isa 为class类型。

    /** 
    * Describes the instance variables declared by a class.
    * 
    * @param cls The class to inspect.
    * @param outCount On return, contains the length of the returned array.
    * If outCount is NULL, the length is not returned.
    * 
    * @return An array of pointers of type Ivar describing the instance variables declared by the class. 
    * Any instance variables declared by superclasses are not included. The array contains *outCount
    * pointers followed by a NULL terminator. You must free the array with free().
    * 
    * If the class declares no instance variables, or cls is Nil, NULL is returned and *outCount is 0.
    */
    
    /** 
    * 描述类声明的实例变量
    * 
    * @param cls 要检查的类
    * @param outCount 有返回 包含返回数组的长度
    * 如果 outCount 为空,长度没有返回
    * 
    * 返回一个ivar类型的指针数组 ,描述这个类声明的实例变量
    * 任何父类声明的实例变量是不包括的 这个数组仅仅包含指针
    *如果指针为空,你必须用free()释放
    * 
    * 如果这个类声明的不是实例变量,或者类为空 返回NULL outCount为0
    */
    
    OBJC_EXPORT Ivar *class_copyIvarList(Class cls, unsigned int *outCount) 
    __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
    “遍历当前类所有的成员变量”
    ==================================================
    /* Working with Instance Variables */
    
    /** 
     * Returns the name of an instance variable.
     * 
     * @param v The instance variable you want to enquire about.
     * 
     * @return A C string containing the instance variable's name.
     */
    /* 操作实例变量 */
    
    /** 
     * 返回实例变量的名字.
     * 
     * @param v 你想要查询的实例变量
     * 
     * @return 一个C语言 字符串 包含实例变量的名字
     */
    OBJC_EXPORT const char *ivar_getName(Ivar v) 
         __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
    “打印成员变量名字”
    ==================================================
    
    /** 
     * Returns the type string of an instance variable.
     * 
     * @param v The instance variable you want to enquire about.
     * 
     * @return A C string containing the instance variable's type encoding.
     *
     * @note For possible values, see Objective-C Runtime Programming Guide > Type Encodings.
     */
    /** 
     * 返回一个实例变量的类型字符串。
     * 
     * @param V 你想查询的实例变量。
     * 
     * @return一个C语言字符串,包含实例变量的类型的 。
     *
     * @有价值的资料,看Objective-C编程指南>类型编码。
     */
    
    OBJC_EXPORT const char *ivar_getTypeEncoding(Ivar v) 
         __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        [self.view setBackgroundColor:[UIColor whiteColor]];
        
        
    // 获得Person类中的所有成员变量
    
        unsigned int count;
        Ivar *ivars =  class_copyIvarList([runModel class], &count);
        for (int i = 0; i<count; i++) {
           Ivar ivar = ivars[i];
            const char *name = ivar_getName(ivar);
            const char *type = ivar_getTypeEncoding(ivar);
            NSLog(@"%s %s", name, type);
        }
        
    
    }
    
    
    ========================控制台打印结果========================
    2016-07-22 16:15:22.086 runrunrun[20039:3797680] _age i
    2016-07-22 16:15:22.086 runrunrun[20039:3797680] _name @"NSString"
    2016-07-22 16:15:22.087 runrunrun[20039:3797680] _height @"NSString"
    2016-07-22 16:15:22.087 runrunrun[20039:3797680] _weight @"NSString"
    2016-07-22 16:15:22.087 runrunrun[20039:3797680] _sex @"NSNumber"
    //  Created by Music on 16/7/12.
    //  Copyright © 2016年 citibank. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    
    @interface runModel : NSObject
    
    
    @property (nonatomic ,copy)NSString *name;
    @property (nonatomic ,copy)NSString *height;
    @property (nonatomic ,copy)NSString *weight;
    @property (nonatomic ,assign)int age;
    @property (nonatomic ,strong)NSNumber *sex;
    
    @end
     分类加属性 应用运行时策略
    
    #import "runModel.h"
    #import "Person.h"
    
    @interface runModel (cate)
    @property (nonatomic ,strong)Person *height;
    - (void)test;
    @end
    
    =============================
    #import "runModel+cate.h"
    #import <objc/runtime.h>
    @implementation runModel (cate)
    
    - (void)test
    {
        NSLog(@"执行test分类方法");
    }
    
    
    static double HeightKey;
    
    - (void)setHeight:(Person *)height
    {
        objc_setAssociatedObject(self, &HeightKey, height, OBJC_ASSOCIATION_ASSIGN);
    }
    
    - (Person *)height
    {
        return objc_getAssociatedObject(self, &HeightKey);
    }
    
    @end
    ===================================
    
      runModel *model = [[runModel alloc] init];
        model.height = p101;
        NSLog(@"---->>>%@",model.height);
    

     runtime方法总结

    1 获取类成员变量名,方法名称

       unsigned int count;
        Ivar *ivars =  class_copyIvarList([runModel class], &count);

    2 关联(分类添加属性)

     objc_setAssociatedObject(self, &HeightKey, height, OBJC_ASSOCIATION_ASSIGN);
     objc_getAssociatedObject(self, &HeightKey);

    3 运行时添加方法

        class_addMethod(self, sel, (IMP)nameGetter, "@@:");

    4 消息转发

     - (id)forwardingTargetForSelector:(SEL)aSelector{}

    5 方法交换

      /** 获取原始setBackgroundColor方法 */
        Method originalM = class_getInstanceMethod([self class], @selector(setBackgroundColor:));
    
        /** 获取自定义的pb_setBackgroundColor方法 */
        Method exchangeM = class_getInstanceMethod([self class], @selector(pb_setBackgroundColor:));
    
        /** 交换方法 */
        method_exchangeImplementations(originalM, exchangeM);
     

    方法相关操作函数

    Runtime提供了一系列的方法来处理与方法相关的操作。包括方法本身及SEL。本节我们介绍一下这些函数。

    方法

    // 调用指定方法的实现
    id method_invoke ( id receiver, Method m, ... );
     
    // 调用返回一个数据结构的方法的实现
    void method_invoke_stret ( id receiver, Method m, ... );
     
    // 获取方法名
    SEL method_getName ( Method m );
     
    // 返回方法的实现
    IMP method_getImplementation ( Method m );
     
    // 获取描述方法参数和返回值类型的字符串
    const char * method_getTypeEncoding ( Method m );
     
    // 获取方法的返回值类型的字符串
    char * method_copyReturnType ( Method m );
     
    // 获取方法的指定位置参数的类型字符串
    char * method_copyArgumentType ( Method m, unsigned int index );
     
    // 通过引用返回方法的返回值类型字符串
    void method_getReturnType ( Method m, char *dst, size_t dst_len );
     
    // 返回方法的参数的个数
    unsigned int method_getNumberOfArguments ( Method m );
     
    // 通过引用返回方法指定位置参数的类型字符串
    void method_getArgumentType ( Method m, unsigned int index, char *dst, size_t dst_len );
     
    // 返回指定方法的方法描述结构体
    struct objc_method_description * method_getDescription ( Method m );
     
    // 设置方法的实现
    IMP method_setImplementation ( Method m, IMP imp );
     
    // 交换两个方法的实现
    void method_exchangeImplementations ( Method m1, Method m2 );
     
  • 相关阅读:
    C#中泛型类,泛型方法,泛型约束实际应用
    Sql语法高级应用之七:如何在存储过程中使用事务
    再探motan
    终于好像懂motan了!!!
    java 反射详解
    设计模式之一工厂方法模式(Factory Method)
    记一次CPU占用率和load高的排查
    浅谈反射性能
    短网址服务(TinyURL)生成算法
    记一次阿里云中间件面试
  • 原文地址:https://www.cnblogs.com/ly1973/p/5695611.html
Copyright © 2020-2023  润新知