美文网首页
ios -- 知识点

ios -- 知识点

作者: 井底蛙之呱呱 | 来源:发表于2017-11-07 08:43 被阅读11次

1、Objective-C的类可以多重继承?可以采用多个协议吗?

    不可以多重继承,可以采用多个协议。

2、Category是什么?扩展一个类的方式用继承好还是类目好?为什么?

     Category是类目。
     用类目好,因为继承要满足a is a b的关系,而类目只需要满足a has a b的关系,
     局限性更小,你不用定义子类就能扩展一个类的功能,还能将类的定义分开放在不
     同的源文件里, 用Category去重写类的
     方法,仅对本Category有效,不会影响到其他类与原有类的关系。

3、延展是什么?作用是什么?

   延展(extension):在自己类的实现文件中添加类目来声明私有方法。

4、类实例(成员)变量的@protected ,@private,@public声明各有什么含义?

    @protected:受保护的,该实例变量只能在该类和其子类内访问,其他类内不能访问。
    @private:私有的,该实例变量只能在该类内访问,其他类内不能访问。
    @public:共有的,该实例变量谁都可以访问。
    @package:包保护的,该实例变量可以被相同框架包中的其他类访问,其他框架包中
                      的类不可以访问

5、id声明的对象有什么特性?

    (1)没有 * 号
    (2)动态数据类型
    (3)可以指向任何类的对象(设置是nil),而不关心其具体类型
    (4)在运行时检查其具体类型
    (5)可以对其发送任何(存在的)消息

6、#import与#include区别

  (1) #import是一个条件预编译语句,作用是将头文件中的所有源代码原封不动
            的置换至当前位置,作用与#include相同
  (2)#import相比#include可以防止交叉编译
   (3) #include需要与#ifndef、#define、#endif条件预编译语句结合使用
             防止交叉编译
   (4) 常用的条件预编译语句: #import、#include、、#define、#elif、
             #else、#ifndef、#if、#endif
   (5) <>导入函数库、框架的头文件,“”导入用户自定义的头文件
   (6) <Foundation/Foundation.h> 中Foundation是框架名称,
             Foundation.h是框架的“主头文件”,

7、简述const关键字的作用

  (1)修饰一般的局部变量,如const int a = 100;  那么a就由变量变成常量,不可以再重新赋值
  (2)修饰指针变量,有以下4种方式
     <1> const int *
     <2>int const * (1)(2)作用相同,变量p的指向可以改变,但是不能通
                                      过p间接改变它指向的内存中的数值
          <3>int * const  变量p的指向不可以改变,但是可以通过p间接改变指向内
                                      存中的数值,定义和初始化必须写在一起
     <4>const int * const   综合了以上2个的特点

8、iOS回传机制 - 委托代理模式

  (1) 把接收数据的类做成代理类(农民)
  (2) 把发送数据的类做成委托类(地主)
  (3) 委托类 - 定义协议;定义一个assign修饰的,采用了协议的一个名为delegate
           的属性;做协议中方法的调用
    (4)   代理类 - 协议中的方法的定义/实现
    (5)   一对一关系

9、委托和委托方双方的property声明用什么属性?为什么?

   (1)委托和委托方双方的property声明属性都是assign而不是retain,为了避免循环
           引用造成的内存泄露。 
   (2)循环引用的问题这样理解:
    ▪   比如在main函数中创建了两个类的对象A和B,现在引用计数都是1。现在让
        A和B互相引用(A有一个属性是B对象,属性说明是retain;B有一个属性是A
        对象,属性说明是retain),现在两个对象的引用计数都增加了1,都变成了2。
    ▪   现在执行[A release]; [B release]; 此时创建对象的main函数已经释放了自己
        对对象的所有权,但是此时A和B的引用计数都还是1,因为他们互相引用了。
    ▪   这时你发现A和B将无法释放,因为要想释放A必须先释放B,在B的dealloc方
        法中再释放A。同理,要想释放B必须先释放A,在A的dealloc方法中再释放B。
        所以这两个对象将一直存在在内存中而不释放。这就是所谓的循环引用的问题。
    (3)要想解决这个问题,一般可以将引用的属性设置为assign,而不是retain来处理。

10、iOS回传机制 - Block块函数

(1)把接收数据的类做 - Block函数的定义
(2)把发送数据的类做 - Block函数的声明和调用

11、iOS回传机制 - 通知

  (1)接收数据的类做通知的注册监听
  (2)发送数据的类做通知的发送
    (3) 注册监听代码 必须 先于发送通知的代码执行!
    (4) 可以实现一对多

12、内存管理的几条原则是什么?按照默认法则,哪些关键字生成的对象需要手动释放?哪些情况下不需要手动释放,会直接进入自动释放池?

(1) OC使用了“引用计数”的内存管理机制
(2)当使用new、alloc或copy方法创建一个对象时,该对象引用计数器为1。如果不需要
        使用该对象,可以向其发送release或autorelease消息,在其使用完毕时被销毁。
(3)当对象调用retain方法时,引用计数值加1;调用release方法时,引用计数值减1;调
        用autorelease方法时,引用计数值不会立即减1,会将对象放入自动释放池,当程序
        退出时,自动释放池会将其中的所有对象的计数值都减1; 如果retain了某个对象,需
        要release或autorelease该对象,保持retain方法和release方法使用次数相等
(4)当引用计数值为0时,系统自动调用dealloc方法,将对象内存销毁
(5)使用new、alloc、copy关键字生成的对象和retain了的对象需要手动释放,即调用
        release方法。设置为autorelease的对象不需要手动释放,会直接进入自动释放池。
(6)使用类方法创建的对象,一般会默认放入自动释放池,不需要手动调用release方法
        去释放其内存,如NSArray *arr = [NSArray arrayWithObjects:@“china”,@“beijing”]; 
        此时arr不需要调用release方法,不然可能会出现内存释放再去调用的崩溃错误!
    NSString *s = [[NSString alloc] init];
    [s release];
        
    NSString *s2 = [[[NSString alloc] init] autorelease];
        
    NSString *s3 = [NSString string];

13、iOS沙盒中三个目录及作用

 (1)Document:用户定义的持久化的文件
 (2)Library:NSUserDefaults持久化的数据、
持久化的底层数据
 (3)Tmp:临时的缓存数据

14、类方法、实例方法

 (1)OC中用+表示类方法,只能由类名调用,不可用对象调用!
 (2)OC中用-表示实例方法/对象方法,只能由对象调用,不可用类名调用!
 (3)成员变量、属性 只能用在实例方法中,不可用在类方法中
 (4)类方法中 使用self、super关键字,只能去调用其他的类方法,不可调用实例方法
 (5)实例方法中,使用self、super关键字,只能去调用其他的实例方法,不可调用类方法

15、extern关键字

 (1)extern+类型+全局变量名称
 (2)作用是申明引用一个外部变量/全局变量
 (3)不会重新申请新的内存空间,去引用全局变量的内存

16、求斐波那契数列

    int finoNum(int month)
    {
            if(month == 1 || month == 2)
                return 1;
            return finoNum(month-1)+finoNum(month-2);
    }

17、Block函数

    /*
    ---------- Block函数声明 ---------
    */
    void (^printConutry_Block)(void);
    double (^getPI_Block)();
    void (^printArgumentsSum_Block)(int,int,int);
    int (^getSum_Block)(int a,int b);

    /*
    ------------  Block函数定义 --------------
    */
    void (^printConutry_Block)(void) = ^(void){
            printf("中国\n");
    };

    double (^getPI_Block)() = ^(){
            return 3.2;
    };

    void (^printArgumentsSum_Block)(int,int,int) = ^(int a,int b,int c){
            printf("sum=%d\n",a+b+c);
    };

    int (^getSum_Block)(int a,int b) = ^(int a,int b){
            return a+b;
    };

    /*
    ------ Block函数调用 --------
    */
    printConutry_Block();   // printMyCountry();
    printf("pi=%g\n",getPI_Block());   // getPI();
    printArgumentsSum_Block(10,20,30);  
    printf("sum=%d\n",getSum_Block(100,200)); // getMax(33, 44)


    (1) Block函数的声明、定义、调用类似于C函数,但是注意写法的不同!
    (2)  C函数特点: 可以嵌套调用、可以递归调用、不可以嵌套定义、不可以使用函数名赋值
    (3)  Block函数特点:可以嵌套调用、可以递归调用、可以嵌套定义、可以使用函数名赋值
    (4)  Block函数的嵌套定义:
    int main(){
        /*
         -- Block函数的嵌套定义 ----
         */
        NSString*(^blockInnerTest)(int,NSString*) = ^(int index,NSString *s){
            
            NSString* sub = [s substringFromIndex:index];
            return sub;
        };
        
        NSString *s = blockInnerTest(2,@"China");
        NSLog(@"%@",s);
        return 0;
    }
    (5)假设新的Block函数的参数、实现都与一个已有的Block函数相同,可以使用函数名赋值

        /*
         Block函数名直接赋值
         */
        int (^sum)(int,int) = getSum_Block;
        NSLog(@"sum=%d",sum(10,20));
        NSLog(@"sum=%d",getSum_Block(10,20));

    (6) 在Block函数体中,只能使用函数体外的局部变量的值,不可以改变局部变量的值;
            如果想在Block函数体中对外部局部变量赋值,方式有3:
             <1> 将外部的局部变量 变成 全局变量
            <2> 将局部变量变为__block变量(两个下划线)
        <3> 将局部变量变为static静态局部变量
    
        __block int innerNum = 200;
          
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            
            innerNum = 200;
        });

    (7)  可以将Block函数做成OC的属性
        @property(nonatomic,strong)void (^Pass)(id data);
            函数名就是OC对象的属性的名称,使用如:  self.Pass...

    (8)  可以将Block函数做成一个类型,并定义其变量
        typedef  void(^blockType)(int,NSString*);  //  blockType变为一个类型说明符

        blockType  a = ^(int num,NSString *str) {
            ………..
        };
        blockType  b ;
        blockType  c = a;    // a、b、c都是blockType类型的变量

17-2、Swift闭包 (等效于OC的Block函数)

     (1)—————   闭包定义 —————
    // 无参数无返回值的闭包
    var blockA:()->Void = {
            print("China")
    }

    // 无参数有返回值
    var blockB:()->Double = {
            return 3.14
    }

    // 有参数无返回值
    var blockC2:(Int,Int)->Void = {
            (x:Int,y:Int)->Void in
                print("尹晓腾")
                print(x+y)
    }

    // 有参数有返回值的闭包
    var blockD:(Int,Double)->Int = {
            (x:Int,y:Double)->Int in
            return x * Int(y)
    }


    (2)——— 闭包定义简化 -------
    var blockD:(Int,Double)->Int = {
            (x:Int,y:Double)->Int in
            return x * Int(y)
    }

    var blockD2:(Int,Double)->Int = {
            (x,y)->Int in
            return x * Int(y)
    }

    var blockD3:(Int,Double)->Int = {
            (x,y) in
            return x * Int(y)
    }

    var blockD4:(Int,Double)->Int = {
            x,y in
            return x * Int(y)
    }

    var blockD5:(Int,Double)->Int = {
            return $0 * Int($1)
    }

    (3)——— 闭包调用 -------
    blockA()

    var pi = blockB()
    print(pi)

    blockC(100,200)

    var res = blockD(100,3.14)
    print(res)

    (4)———— 函数类型作为另一个函数的形参 ————
    func test(num:Int,dNum:Double)->Int {
            return num + Int(dNum)
    }

    func showTest(a:Int,b:Double,c:(Int,Double)->Int)->Void{
            print(c(a,b))
    }

    showTest(a: 100, b: 3.14, c: test)

    
    (5)———— 闭包代替同类型的函数类型作为另一个函数的形参 ————
    func showTest(a:Int,b:Double,c:(Int,Double)->Int)->Void{
            print(c(a,b))
    }

    showTest(a: 100, b: 3.14, c: blockD)  

    showTest(a: 100, b: 3.14, c: {
            (x:Int,y:Double)->Int in
            return x / Int(y)
    })

    showTest(a: 100, b: 3.14, c: {
            x,y in
            return x +  Int(y)
    })

    showTest(a: 100, b: 3.14, c: {
            return $0  -  Int($1)
    })

    (6)———— 尾随闭包 ————
    showTest(a: 100, b: 3.14) { (x, y) -> Int in
            return x % Int(y)
    }

    (7)—— 系统提供的带闭包的方法调用 ——
    var arr = [21,3,15,7,32,19]
    var sortArr =  arr.sorted()
    print(sortArr)

    // 闭包表达式方式
    sortArr = arr.sorted(by: {
            x,y in
            return x > y 
    })

    // 尾随闭包方式
    sortArr =  arr.sorted { (x, y) -> Bool in
            return x > y
    }

    sortArr =  arr.sorted { x, y in
            return x > y
    }

    sortArr =  arr.sorted {
            return $0 > $1
    }

    sortArr =  arr.sorted {
            $0 > $1
    }

18、iOS持久化技术

  (1)plist文件持久化 (writeToFile)
  (2)sqlite3 - 嵌入式的小型数据库,C函数 (中型MySQL、  SQLServer)  (Oracle、DB2  大型)
  (3)NSUserDefaults - 参数持久化
  (4)CoreData (苹果封装的,以SQLite3底层实现的持久化框架,OC方法
    第三方 FMDB (底层也是使用SQLite3实现)

19、pch文件使用

 (1)pch是整个工程的条件预编译的头文件
 (2)在该文件中定义的符号 可以在工程的每个文件中直接使用 而不用再声明
 (3)添加方式 - <1> NewFile - OtherFiles - PCH File
                        <2> 在工程设置的BuildSettings选项中,找到Apple LLVM Language - PrefixHeader选项,
                               在右侧空白添加创建的pch文件的路径 - $(SRCROOT)/工程目录名称/pch文件全称

20、NSStringFromSelector(_cmd)
_cmd表示本方法的 @selector/SEL 封装

21、nil、NULL、Nil、NSNull区别

  (1)nil表示对象指向空,如:NSString *s = nil; 
      nil对象调用方法,编译、运行都不崩溃,只是什么都不执行!
  (2)NULL表示指针为空,用于C语言的指针,如 int *p = NULL;
  (3)Nil 表示类为空
  (4)NSNull表示空对象,NSArray *arr = [NSArray arrayWithObjects:@“yin”,@“wang”,nil,@“china”,@100,nil];
        nil 在此处表示数组成员的一个结束标志,不是数组的成员,而且数组会以第一个出现的nil作为结束标志!
    如果想在数组中添加一个空对象作为数组的成员,必须使用NSNull类,NSNull类只有一个对象的创建方式,
        即[NSNull null]
    NSArray *arr = [NSArray arrayWithObjects:@"1",@23, [NSNull null],@"china",@100,nil];

22、Plist持久化关于自定义类对象的持久化

  (1) NSString、NSArray、NSDictionary自带writeToFile方法,可以直接将字符
          串、数组、字典数据写入文件中保存
  (2)如果将自定义对象写入文件,或者将自定义对象加到数组或字典中将数组或
          字典写入文件,都需要对自定义类做归档操作
  (3)OC对自定义类做归档操作,须采用NSCoding协议,实现协议的两个方法:
          <1>encodeWithCoder:
       <2>initWithCoder:
    (4) 对自定义类做归档操作后,还需要使用NSKeyedArchiver序列化类将自定义对
         象转换为二进制数据写入文件,使用NSKeyedUnArchiver反序列化类将持久化
         的二进制数据读取转换为OC的对象类型

23、SQL语句

  (1)DDL语句:(数据库定义语句)   create、drop、alter
      <1>create语句:
    "CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT,password TEXT,phone TEXT UNIQUE)"
  (2)DML语句: (数据库操作语句)insert、update、delete、select
         <1>insert语句:
        "INSERT INTO users (name,password,phone) VALUES (?,?,?)”
     <2>update语句:
        "UPDATE users SET name = ? , password = ? WHERE id = ?”
     <3>delete语句:
        "DELETE FROM users WHERE id = ?”
     <4>select语句:
        "SELECT * FROM users"
        "SELECT name,password FROM users where id > 5 and id < 10”
        “SELECT name \’姓名\’,password \’密码\’ FROM users where phone like \’133\%\’ “

24、单例模式

 (1)不管实例化多少个对象,都指向同一块内存空间,这样的类叫单例类
 (2)iOS提供的单例类:
        [NSFileManager  defaultManager]、[UIApplication  sharedApplication]、
        [UIScreen  mainScreen]、[UIDevice  currentDevice]、
        [NSNotificationCenter  defaultCenter]、
    [NSUserDefaults standardUserDefaults]
 (3)怎样自定义单例类:
       <1> 在类的.m文件中定义一个static修饰的本类的全局对象,并赋值为nil
    <2>在类的.h文件中声明一个类方法,以让外部类获取唯一的单例对象内存
    <3>在类的.m文件中定义.h中声明的类方法,使用懒加载方式创建单例对象内存
    <4>在类的.m文件中重写allocWIthZone:方法,使用懒加载方式实现代码,保证
          使用alloc方法创建对象时,只得到一块内存
    <5>采用NSCopying协议,实现协议中的copyWithZone:方法,使用懒加载方式
          实现代码,防止对象调用copy方法时生成新的内存空间
    <6>采用NSMutableCopying协议,实现协议中的mutableCopyWithZone:方法,
             使用懒加载方式实现代码,防止对象调用mutableCopy方法时生成新的内存空间
    <7>在MRC环境下,重写retain和release方法,防止内存计数的改变,让单例类内存
         的计数值永远是1,只有程序退出时将内存计数值减1然后销毁

25、instancetype与id的区别?

    (1)instancetype可以用在任何类中,代表所在类的对象类型
    (2)id可以表示任意类的对象类型
    (3)instancetype一般只能用作方法的返回值类型,不可以用作方法的参数类型,
        不可在方法内部使用它作为类型说明符定义对象
    (4)id既可以作为方法返回值类型,也可作为方法参数类型,也可在方法内部使用
        它作为类型说明符定义对象
    (5)id类型的对象可以调用所有类中定义的任何一个公开的方法,编译都成功!但是
               运行可能会崩溃,要去注意id对象的运行类型是什么!
    (6)NSObject类提供了判断id对象运行类型的两个方法:
               <1> isKindOfClass: - 判断是不是某个类或其子类的对象类型
        <2>isMemberOfClass: - 判断是不是某个类(不包含其子类)的对象类型
    (7)id类型对象不可以调用类中的属性,如果想调用,必须将id对象强制装化为某个类的
        类型,如: 
        id obj = [[Student alloc] init];    
        obj.name = @“尹晓腾”; // 调用编译报错
        Student *s = (Student *)obj;   // 必须强制转化
        s.name = @“尹晓腾”;   // 才可以调取类中的属性
        ((Student *)obj).name = @“王梅”;    // OK!

26、深拷贝、浅拷贝区别?

     (1)对于Foundation框架提供的类,比如字符串、数组、字典,实现浅拷贝代码如下:
         NSArray *arr = @[@“china”];   
         NSArray* arr2 = arr;   // <1> 直接用对象名赋值
         NSArray* arr3 = [arr copy];   // <2> 不可变对象调用copy
         “浅拷贝”实现的是对象“地址”的复制,两个对象都指向同一块内存空间;
             其中一个对象销毁,另一个对象就不能再使用;
             对于可变数组或字符串,一个对象改变内容,另一个对象的内容也跟着改变。
             
     (2)对于Foundation框架提供的类,比如字符串、数组、字典,
            实现深拷贝代码如下:
         NSArray* arr = @[@“china”];   
         NSMutableArray *arr3 = [arr mutableCopy];   // <1>不可变对象调用mutableCopy
         NSArray* arr4 = [arr3 copy];   // <2>可变对象调用copy方法
         “深拷贝”实现的是对象“内容”的复制,两个对象都指向两个不同的内存空间,但是内存中的内容相同;
         其中一个对象销毁,另一个对象不受影响,可以使用;
             对于可变数组或字符串,一个对象改变内容,另一个对象的内容不会跟着改变。
         
     (3)注意copy和mutableCopy的使用!
            <1> 不可变对象调用copy实现的是浅拷贝
        <2> 可变对象调用copy、mutableCopy;不可变对象调用mutableCopy实现深拷贝
        <3> 如果生成可变对象时错调用了copy方法,如下:
           NSArray* arr = @[@“china”];   
              NSMutableArray *arr3 = [arr copy];   // 应改为mutableCopy
                 那么arr3调用NSArray的方法,调用NSMutableArray的方法,编译都成功;
                 但是运行NSArray方法成功,运行NSMutableArray方法时会崩溃
        <4>如果生成不可变对象时错调用了mutableCopy方法,如下:
           NSArray* arr1 = @[@“china”];   
              NSMutableArray *arr2 = [arr1 mutableCopy];
                  NSArray* arr3 =  [arr2 mutableCopy];    // 注意!
              那么arr3不能调用NSMutableArray的方法,编译报错;
                  arr3可以调用NSArray的方法,编译、运行都成功!

          但如果写为如下方式:
                 NSArray* arr1 = @[@“china”];   
              NSMutableArray *arr2 = [arr1 mutableCopy];
                 id arr3 =  [arr2 mutableCopy];
          那么arr3既可以调用NSArray方法,又可以调用NSMutableArray方法,
                 编译、运行都成功!
            <5> @property(nontomic,copy)NSMutableString *str; 
                   self.str = [[NSMutableString alloc]  init];
            [self.str appendString:@“china”];   // 出错,运行崩溃
            [self.str stringByAppendingString:@“china”]; 

        (4)自定义对象实现深拷贝
                <1> 自定义对象调用copy方法,如:
               Student *s = [[Student alloc] init];
               Student *s2 = [s copy];
        <2>使用copy方法,
                     A:必须在自定义类中重写-(id)copy;方法
                     B:  采用NSCopying协议,实现协议中的copyWithZone:方法
        <3>使用第<2>步中的两个方法,可以调用copy,但不一定就是深复制,关键看代码如何去写!
      (5)
        <1> 不可变对象 调用 copy 实现“浅拷贝”,得到一块“不可变”的内存
        <2> 不可变对象 调用 mutableCopy 实现“深拷贝”,得到一块“可变”的新内存
        <3> 可变对象  调用copy 实现 “深拷贝” ,得到一块“不可变”的新内存
        <4> 可变对象  调用mutableCopy 实现 “深拷贝” ,得到一块“可变”的新内存

27、self和super的区别?

(1)self是类的隐藏的参数变量,用在方法(类方法、实例方法)内部,表示调用该方法的类或对象
(2)super不是类的隐藏的参数,只是一个“编译器指示符”,表示从调用该方法的类或对象的父类中
        去查找对应的属性或方法
(3)self与super都指向同一个对象,只是查找方法的位置不同,一个从本类中,一个从本类的超类中
(4)假设类Student继承自Human,在子类中有代码如下
    NSLog(@"%@",NSStringFromClass([self class]));
    NSLog(@"%@",NSStringFromClass([super class]));
    结果都是Student
(5)self调用方法在runtime机制中调的函数是objc_msgSend(id self,SEL _cmd,…);
        super调用方法在runtime机制中调用函数是objc_msgSendSuper(struct objc_super *super,SEL _op…);
        struct objc_super{
        id receiver;
        Class superClass;
    };

                        LoginRegister  - 登录注册
                        News  - 新闻
                        Weather - 天气预报

Codes - Ticket - 票务查询
Personal - 个人信息
Services - 业务类
Category - 类别

                             Videos  - 视频

Soruce - Images - 图片
Music - 音乐
Files - 其他文件

Third - 第三方文件

28、pt、px区别?

(1)px表示像素值
  (2) pt表示开发点

29、NSObjcRunTime方法?

(1)NSString *NSStringFromClass(Class aClass);
  (2) Class _Nullable NSClassFromString(NSString *aClassName);

30、iOS获取App当前的版本号代码

NSString *currentVersion = [[NSBundle mainBundle].infoDictionary objectForKey:@"CFBundleShortVersionString"];

31、导航条与UIScrollView冲突解决方法

(1)在添加UIScrollView的ViewController中添加代码
    self.edgesForExtendedLayout = UIRectEdgeNone;
(2)在添加UIScrollView的ViewController中添加代码
    self.automaticallyAdjustsScrollViewInsets = YES;
(3)如果以上两种方法都不可以解决,使用下面方法:
    在添加UIScrollView的ViewController中添加代码:
    UIView *v = [[UIView alloc] init];
    [self.view addSubview:v];

    然后再正常添加UIScrollView即可

32、响应者链(Responder Chain)

(1)响应者对象(Responder Object)指的是有响应和处理“事件/消息/方法”能力的对象
(2)响应者链就是由一系列的响应者对象构成的一个层次结构
(3)UIResponder是所有响应对象的基类。我们常用的UIApplication、UIViewController、
        UIWindow和所有继承自UIView的类都直接或间接继承自UIResponder
(4)响应者链事件传递过程:
        <1> 一般view是响应者链中事件的第一响应者 
        <2> view不响应事件,如果view是控制器的view,就传递给控制器,如果不是,就传递给view的父视图
     <3> 父视图同样按照第<2>步的方式响应事件,直至将事件传递给视图层次结构的最顶级视图
     <4> 如果顶级视图也不响应事件,将事件传递给window对象处理
     <5> window对象不处理的话,传递给UIApplication对象处理
     <6> UIApplication对象也不处理,事件将被丢弃
   (5) 实际应用,View与Controller分离,在View中获得所在的Controller对象
    -(UIViewController *)viewController {
    // 使用响应者链的方式,获得self所在的Controller对象
    for (UIView *preView = self; preView; preView = self.superview) {
                UIResponder *next = preView.nextResponder;
                if ([next isKindOfClass:[UIViewController class]]) {
                    return  (UIViewController *)next;
                }
            }
            return nil;
    }


33、BOOL、boolean

(1)C语言是没有布尔类型,用0值表示假,用非0值表示真
    int a = -10;
    if(a){ }      表示逻辑为真!

    if(50<a<100) { }      // 可以如此书写,编译OK,但是不管a为什么数值,条件永为真! 
     
(2)C++、Java中使用boolean表示布尔类型,数值包括true、false
    Java中不支持用0值表示假,用非0值表示真的写法!
    int a=10;
    if(a) {     // Java中如此书写编译报错!
    }

    if(50<a<100) { }      // 不可以如此书写,编译错误!

(3)OC中使用BOOL表示布尔类型,数值包括YES、NO;
    因为OC是从C扩展而来,在OC中,也可以使用0值表示假,用非0值表示真

34、Mac终端命令(Unix、Linux命令)

(1)/              系统根目录
(2)~              用户根目录
(3).              当前目录
(4)..             上一级目录
(5)cd           切换目录
(6)ls(-a)   展示当前目录中所有的文件及子目录  
(7)mkdir       创建新目录
(8)rm -rf      删除目录
(9)rm           删除文件

35、%@与-(NSString *)description方法

(1)任意一个Foundation的OC的对象都可以使用%@执行打印操作
(2)Foundation中的类的对象使用%@打印可以显示内容
(3)自定义对象使用%@打印,出现 <类名:0xfffffff> 的内容,显示的是类名和对象的地址
(4)如果想用%@打印自定义对象时能显示对象的属性信息,须在自定义类中重写-(NSString *)description方法

36、获取沙盒中的Documents目录路径的三种代码方式

        // (1)
        NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
        // (2)
        NSString *documentPath2 = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
        // (3)
        NSURL *documentURL = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];

37、获取某个指定范围的随机数

    假设要获取M到N的随机数(M<N),可套用以下公式:
    int ranNum =  M + arc4random() % (N-M+1);
    假设取出33到69的随机数
    33 + arc4random() % (69-33+1);

38、iOS获取键盘高度

    (1)注册监听,监听键盘的弹出
        [[NSNotificationCenter defaultCenter] addObserver:self 
            selector:@selector(handleKeyBoardNotification:) 
                name:UIKeyboardWillShowNotification 
              object:nil];
    (2)在监听的触发方法当中,使用如下代码获取键盘高度
        -(void)handleKeyBoardNotification:(NSNotification *)sender {
   
             // 获取键盘高度,关键的一句
                NSValue *value = [sender.userInfo objectForKey:@"UIKeyboardBoundsUserInfoKey"];
                CGSize keyboardSize = [value CGRectValue].size;
                float keyboardHeight = keyboardSize.height;
            }

39、属性修饰符

        strong:强引用,会将参数对象的“引用计数”值加1,一般用来修饰OC的对象类型,
            不可以修饰基本类型!用在ARC环境下
        @property(nonatomic,assign)NSString *s;   
        // (MRC环境)用assign修饰s,调用以下两段代码,程序可能会崩溃
        // 用strong修饰s,就OK

        -(void)test {
            self.s = [[NSString alloc] init];
            [self.s release];
        }

        -(void)sss {
            NSLog(@“%@”,self.s);
        }
        retain: 强引用,同上,一般用在MRC环境下
        assign:弱引用,对参数对象的“引用计数”值不做任何修改,一般修饰基本类型,
            但是也可以修饰OC的对象类型,在委托代理模式中,
           修饰委托类的id  delegate属性一般用assign,防止循环引用(retain cycle)
        weak:弱引用
    copy:复制,对参数对象做复制操作,可能是深复制,也可能是浅复制,参考26
        @property(nonatomic,copy)NSString *s;
        NSString *name = @“China”;
        self.s = name;   // 因为参数是一个不可变对象,不可变对象调用copy实现浅拷贝
        [self.s stringByAppendingString:@“Beijing”];   // 编译、运行都OK!
        [self.s appendString:@“Beijing”];  // 编译报错!


        NSMutableString *country = [NSMutableString stringWithUTF8String:”Beijing”];
        self.s = country;   // 因为参数是可变对象,可变对象调用copy实现深拷贝
        [country appendString:@“Bawei”];
        NSLog(@“%@”,self.s);     // Beijing
        NSLog(@“%@”,country);   // BeijingBawei 
        [self.s stringByAppendingString:@“Beijing”];   // 编译、运行都OK!
        [self.s appendString:@“Beijing”];  // 编译报错!

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

        @property(nonatomic,copy)NSMutableString *s;
        NSString *name = @“China”;
        self.s = name;   // 因为参数是一个不可变对象,不可变对象调用copy实现浅拷贝
        [self.s stringByAppendingString:@“Beijing”];  //  编译,运行都OK!
        [self.s appendString:@“Beijing”];  // 编译OK,运行崩溃

        NSMutableString *country = [NSMutableString stringWithUTF8String:”Beijing”];
        self.s = country;   // 因为参数是可变对象,可变对象调用copy实现深拷贝
        [country appendString:@“Bawei”];  
        NSLog(@“%@”,self.s);     // 内容还是“Beijing”
        NSLog(@“%@”,country);   // 内容是“BeijingBawei”

        [self.s stringByAppendingString:@“Beijing”];  //  编译,运行都OK!
        [self.s appendString:@“Beijing”];  // 编译OK,运行崩溃
    
    nonatomic:非原子性操作,多线程不安全的,一般选择nonatomic修饰属性,在非多线程开发中提高性能
    atomic:原子性操作,多线程安全的(如果在多线程开发中,多个线程同时对一个可变对象做修改,可以使用该修饰符)
    readwrite:可读写的,生成setter方法和getter方法
    readonly:只读的,生成getter方法,没有setter方法

40、 #include<stdio.h>

    (1)标准输入输出函数库
     (2)printf()、scanf()、fgetc()、fputc()、fgets()、fputs()、fread()、fwrite()、fprintf()、fscanf()

    #include<string.h>   C语言字符串操作函数库
    strcpy()   字符串拷贝
    strcmp()   字符串比较

    #include<math.h>   // 数学函数库
    
    #include<windows.h>   // 

41、OC语言的优缺点

(1)优点:
        <1>
        <2>
  (2) 缺点:
        <1> 不可以做类型安全判断


42、C、OC语言数据占位符

(1)整数字面常量
    int num = 35;    // 35表示十进制数 35
    int num = 035;   // 35表示八进制数35
       int num = 0x35;  // 35表示十六进制数35 

(2) 整形占位符
    <1> %d : 十进制方式
    <2>%+-md : 十进制方式打印,但是如果m的绝对值小于等于数字实际占用列数,原样输出;
                      如果m的绝对值大于实际列数,正数(+)左补空格凑成m列打印,
                  负数右补空格凑成m列 
        printf(“A%4dZ”,12);    // A  12Z(A和12之间有2个空格)
        printf(“A%-4dZ”,12);    // A12  Z(12和Z之间有2个空格)  
        printf(“A%4dZ”,1314);    // A1314Z

    <3>%0md : 如果m的值小于等于数字实际占用列数,原样输出;
                      如果m的值大于实际列数,左补0凑成m列打印
        printf(“%04d”,12);    // 0012
        printf(“%04d”,1314);    // 1314
    
    <4> %o : 八进制方式打印
    <5> %x : 十六进制打印
    <6> %u : 无符号整型(unsigned int) 、无符号短整型(unsigned short)打印方式
    <7> %lu: 无符号长整型数(unsigned long)打印方式
    <8> 二进制、八进制、十六进制  转为 十进制
          以0开始从最后一个数字向前排序,让序号上的数字乘以2/8/16的对应的序号次方,相加
    <9> 十进制转换为二进制、八进制、十六进制
             对十进制数字辗转除2/8/16取余数,将余数倒置

(3)浮点型
    <1> %lf - double类型
    <2>%f - float类型
    <3>%g - 可以把小数点后面无用的0去掉不显示!
    <4>%+-m.nlf   -  占位列数打印浮点型数据
        m表示打印的数字占用多少列,如果实际列数大于等于m,原样输出;如小于m,为正数左补空格补全,
        为负数,右补空格补全!
        n表示小数点后保留几位
        
        printf("%lf\n",3.14);   // 3.140000
            printf("%9lf\n",3.14);  // _3.140000 (前面有1个空格)
        printf("%-9lfAAAA\n",3.14);   // 3.140000_AAAA
            printf("%9.2lf\n",3.148);   // _____3.15(前面有5个空格,进行四舍五入!!!)
        printf("%-9.2lfAAAA\n”,3.148);   // 3.15_____AAAA(中间有5个空格,进行四舍五入!!!)
        
(4)字符型
    %c

(5)字符串型
    <1> %s
    

43、C语言字符串表示方式及使用

(1)字符数组存储字符串
    char name[100]  = “China”;
    name = “Beijing”;   // 编译错误!!在C当中,数组名表示的是一个地址常量符号,代表数组首元素的地址!
                                   // 此处的name等价于&name[0] ,但是是一个常量符号!
    
        char name[100]  = “China\0Beijing\0”;
    printf(“%s”,name) ;     // 打印结果为China

    <1> 在C当中,数组名表示的是一个地址常量符号,代表数组首元素的地址
    <2> ‘0’与‘\0’ 不同,‘\0’表示字符串结束标志,打印时并不显示;’0’就是一个一般的字符,打印时显示0
        ‘0’ASCII码值为48
        ‘\0’ASCII码值为0
    <3> 如果想对name数组重新赋值,必须使用字符串操作函数
        strcpy(name, "Ba");
    <4>如果比较两个字符串内容是否相同,使用C的字符串操作函数strcmp
        if (strcmp(name, "Ba")==0) {
                printf("想等");
            }
        else{
                printf("不等!");
            }
    <5>char name[100] = “China”;  printf(“%ld”,sizeof(name));   // 结果是100
         char name[] = “China”;  printf(“%ld”,sizeof(name));    // 结果是6

(2)字符指针指向字符串
    char *name = “beijing”;
    name = “China”;
    printf(“%s\n”,name);
    strcpy(name,”bawei”) ; // 编译OK,运行崩溃!
    printf(“%ld”,sizeof(name));   // 不管内容如何变化,永远是8!

    <1>  在同一环境下,int*、double*、float*、char*占用内存大小都是相等的!!
    
 

44、需要记住的ASCII码值

    (1)  ’0’  -  48
    (2) ‘A’  -  65
    (3) ’a’  -  97
    (4) ASCII码值为0的三种表示:
        <1> 整数0
        <2> 字符串结束标志’\0’
        <3> NULL

45、Swift整型数据表示范围

(1)  Int8         -2^7 ~ 2^7-1               -128 ~ 127
(2) Int16        -2^15 ~ 2^15-1            -32768 ~ 32767
(3) Int32       -2^31 ~ 2^31-1            -2147483648 ~ 2147483647
(4) Int64       -2^63 ~ 2^63-1      -9223372036854775808 ~ 9223372036854775807
(5) UInt8       0 ~ 2^8-1                    0 ~ 255
(6) UInt16      0 ~ 2^16-1                   0 ~ 

46、整型数据在计算机内存中的存储

(1)整数在计算机中以补码方式存储
(2)正数的符号位为0,补码与原码相同
(3)负数的符号位为1,补码获得需要经过 原码 - 反码 - 补码
   
    正数15    Int8 num = 15
                     原码: 00001111    (标红的为符号位,0表示正数)
       内存存储 :            补码: 00001111

    负数-15  Int8 num = -15
                  原码 :10001111
                            反码: 11110000
    内存存储 :     补码: 11110001


    内存中数据:   11111111
    数值:   -1

47、Swift类型推断及类型安全

(1)var num:Double = 3.14
    num = 100  // OK!
  (2) var num:Int = 100
    num = 3.14  // 报错!
  (3) 不同类型的变量或常量相互赋值,必须做类型转换!不能直接赋值
    var num:Int8 = 100
    var x:Int16 = 100
    num = x   // 报错!   改为num = Int8(x)
    x = num   // 报错!   改为x = Int16(num)

    var y:Double = 3.14
    y = num  // 报错       改为 y = Double(num)
    num = y   // 报错!   改为num = Int8(y)     结果得到3
 

48、Swift十六进制浮点型表示方式

(1)0xfp2      15*2^2 = 60
  (2) 0xfp-2     15*2^-2 = 3.75
  (3) 0xf.3p0     (15+3/16)*(2^0)   =  15.1875
  (4) 0xf.32p0   (15+3/16+2/16/16) * (2^0) = 15.1953125

49、C、OC、Swift中的转义字符

(1)“\0”     字符串结束标志,空
  (2) “\n”     换行
  (3) “\t”      水平制表符
  (4) “\r”      回车符
(5)”\\”     1个\
(6)“\’”      1个’
(7)”\””      1个”
(8)”\u{1f4b}”      1个Unicode字符

50、自定义对象放入NSSet集合需要做的操作

      (1)因为NSSet集合要求放入其中的元素不重复
    (2)  自定义对象判断重复默认是根据对象的地址来判断,
      (3)地址相同的对象不会重复放入,地址不同但内容相同的对象也都会放入集合中
      (4)为了将内容相同的自定义对象不重复放入集合中,须做以下两个操作
               在自定义类中重写以下两个方法:
        <1>
            -(BOOL)isEqual:(id)object {
                // 如果object不是本类或本类的子类的对象,直接返回NO表示内容不相同!
                if (![object isKindOfClass:[Human class]]) {
                    return NO;
                }
                // 如果object是本类或本类子类的对象,比较所有的属性是不是相同的,都相同返回YES,否则返回NO
                Human *obj = (Human *)object;
                return [self.name isEqualToString:obj.name] && self.age==obj.age && 
                  [self.address isEqualToString:obj.address];
        }
        <2>
            // 重写哈希值方法,所有属性的哈希值相加,将其中某一个乘以较大质数,用来判断两个对象相不相同
        -(NSUInteger)hash {
                return  67 * [self.name hash] + self.age + [self.address hash];
        }
    (5)这两个方法是NSSet判断集合中元素是否相等的方法,如果调用isEuqal方法为YES并且比较的两个对象的哈希值相等
        那么NSSet就认为比较的两个对象相同,不能重复放入集合中;否则认为不同,可以都放入集合中

51、sizeof、strlen对于C字符串数组求值

   (1)
   char city[100] = “China”;
    printf("%ld\n",sizeof(city));  // 100,方括号中的数字就是内存划分的数组大小,sizeof(char) * 100 = 100
    printf("%ld\n",strlen(city));  //  5
       city[7] = ‘V’ ;     // 可以赋值
        printf(“%s\n”,city) ;    // 结果还是China  内存存储为 ‘C’ ’h’ ‘i’ ’n’ ‘a’ ‘\0’ ‘\0’ ‘V’  打印遇到第一个‘\0’就停止!
    (2)
   char city[] = “China”;
    printf("%ld\n",sizeof(city));  // 6,方括号中没有数字系统根据初始化的字符串的总个数加1作为数组的长度
    printf("%ld\n",strlen(city));  //  5
       city[7] = ‘V’;   // 数组长度就是6,下标必须在0-5之间,7已经越界
       printf(“%s\n”,city) ;    //  崩溃!

52、Swift字符与ASCII数值相互转换

(1)将字符转为整数值
    var a:Character = "A"
    var str = String(a)
    var number:UInt32 = 0
    for code in str.unicodeScalars {
            number = code.value;
    }
    print(number)

(2)将整数转换为字符
    var num = 97
    var ch:Character = Character(UnicodeScalar(num)!)
    print(ch)

53、 把一个字符串中的字符变换,大小字母变为小写字母,小写字母变为大写字母,其他的不变

(1)C、OC代码实现
       char city[] = "cHina1314BeiJing";
    printf("%s\n",city);
    
    for (int i = 0; i < strlen(city); i ++) {
        if ( city[i] >= 'a' && city[i] <= 'z' ) {
            city[i] -= 32;
        }
        else if (city[i] >= 'A' && city[i] <= 'Z'){
            city[i] += 32;
        }
    }
    
    printf("%s\n",city);

(2)Swift实现
    /*
    函数,将大写字母变小写,小写字母变大写,其他字符不变
    */
    func changeCharacter(chNum:Character) -> Character {
            /*
            将字符转换为整数
            */
            var chStr = String(chNum)  // 将字符转为字符串
            var num:UInt32 = 0    // 用于接收字符整数值的变量
            for item in chStr.unicodeScalars {
                num = item.value   // 循环只执行一次,获取字符的整数值
            }
    
            /*
            如果是大小写字母,转换数值
            */
            // 如果是大写字母,转换为小写
            if num >= 65 && num <= 90 {
                num += 32
            }
            // 如果是小写字母,转换为大写
            else if num >= 97 && num <= 122 {
                num -= 32
            }
    
            /*
             将整数转换为字符
            */
            var newChNum = Character(UnicodeScalar(num)!)
            return newChNum
    }

    
    /*
    函数调用改变字符串
    */
    var string = "china#488BeiJIng"  // 测试的字符串
    print(string)
    var i = 0  // 表示偏移量(循环变量初始值)
    while i < string.characters.count {  // 循环条件,包含循环变量的终止值
            var ch = string[string.index(string.startIndex, offsetBy: i)]
            string.replaceSubrange(string.index(string.startIndex, offsetBy:    
                i)...string.index(string.startIndex, offsetBy: i), 
                with: String(changeCharacter(chNum: ch)))
            i += 1   // 循环变量值变化
    }
    print(string)

54、Swift中以二进制、八进制、十六进制方式打印整数

    /*
    将一个整数用二进制方式打印
    */
    func binaryPrintIntNumber(num:Int) {
            var remainderArr:[Int] = []  // int数组,存储余数
            var quotient:Int = num  // 表示商的变量,初始值是num
            while quotient > 0 {   // 商的终值是0
                let remainderNum = quotient % 2 // 获取余数值
                remainderArr.insert(remainderNum, at: 0) // 插入数组中
                quotient /= 2   // 商变化
            }
            for item in remainderArr {
                print(item, terminator: "")
            }
            print("")
    }

      /*
    将一个整数用八进制方式打印
    */
    func octalPrintIntNumber(num:Int) {
            var remainderArr:[Int] = []  // int数组,存储余数
            var quotient:Int = num  // 表示商的变量,初始值是num
            while quotient > 0 {   // 商的终值是0
                let remainderNum = quotient % 8 // 获取余数值
                remainderArr.insert(remainderNum, at: 0) // 插入数组中
                quotient /= 8   // 商变化
            }
            for item in remainderArr {
                print(item, terminator: "")
            }
            print("")
    }

55、OC数组排序

(1)自带的compare:方法排序(如果数组元素是字符串,按照字符串的ASCII值排序;如果是NSNumber,按照数值排序)
    NSArray *names = @[@"China",@"Beijing",@"Tianjin",@"SHanghai"];
    NSLog(@"%@",[names sortedArrayUsingSelector:@selector(compare:)]);
    结果:Beijing,China,SHanghai,Tianjin

(2)一些实际需求中不能用compare:排序,需要自己制定排序算法
    NSArray *arr = @[@"15",@"23",@"45",@"3",@"123"];
    NSArray *sortedArr = [arr sortedArrayUsingSelector:@selector(compare:)];
    NSLog(@"%@",sortedArr);
    结果:123,15,23,3 , 45

    // 如果想按照字符串的数值来排序,需要自己制定排序算法,代码实现如下:
    sortedArr =  [arr sortedArrayUsingComparator:^NSComparisonResult(id  _Nonnull obj1, id              _Nonnull obj2) {

            return [obj1 intValue] > [obj2 intValue];
      }];
    NSLog(@"%@",sortedArr);
    结果:3,15,23,345,123

56、Swift构建单例类

    class DataBase {
            static var defaultDB:DataBase? = nil
            var name = ""
    
         private init() {
        
            }
    
    
            static func shared() -> DataBase {
                if defaultDB == nil {
                        defaultDB = DataBase()
                }
                return defaultDB!
            }
    }

57、Swift使用++、—-运算符

(1)Swift的Int类型不再支持自增减运算符比如,++a,a++, —a, a—
       的方式
(2)如果想让Swift支持这种语法,须重载运算符
       extension Int{
    // 前++
        static prefix func ++(num:inout Int) -> Int {
            num += 1
            return num
        }
    
    // 后++
        static postfix func ++(num:inout Int) -> Int {
            let temp = num
            num += 1
            return temp
        }
    
    // 前—
        static prefix func --(num:inout Int) -> Int {
            num -= 1
            return num
        }
    
    // 后—
        static postfix func --(num:inout Int) -> Int {
            let temp = num
            num -= 1
            return temp
        }
    }
    

58、OC的runtime

(1)runtime是一套比较底层的纯C语言API, 属于1个C语言库, 包含了很多底层的C语言API。 
(2)在我们平时编写的OC代码中, 程序运行过程时, 其实最终都是转成了runtime的C语言代码, runtime算是OC的幕后工作者 
(3)比如说,下面一个创建对象的方法中, 举例: 
        OC : [[MJPerson alloc] init] 
        runtime : objc_msgSend(objc_msgSend("MJPerson" , "alloc"), "init")
(4)用处:
    <1> 在程序运行过程中, 动态创建一个类(比如KVO的底层实现)
        Class MyClass = objc_allocateClassPair([NSObject class], "MyClass", 0);

     <2> 在程序运行过程中, 动态地为某个类添加属性, 修改属性值
        BOOL isSuccess = class_addIvar(MyClass, "test", sizeof(NSString *), 0, "@");
        参数1: 类名
        参数2: 属性名
        参数3: 开辟属性占用内存大小(单位为字节)
        参数4:对齐方式
        参数5:参数类型,“@”官方解释为对象、静态类型或id类型,其他类型参考官网
                https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/               ocrtTypeEncodings.html
        返回值:BOOL,是否添加成功

    <3> 在程序运行过程中, 动态地为某个类添加方法
        (A)
        class_addMethod(MyClass, @selector(addMethodForMyClass:), (IMP)addMethodForMyClass, “V@:”);
        参数1: 类名
        参数2: SEL方法名
        参数3: IMP指针(IMP是implementation缩写),指向一个函数的指针,每个方法都有一个对应的IMP
        参数4: 方法的参数,
                  若为“i@:@”表示返回值为int,第一个参数为id类型,:表示@selector(_cmd),第2个参数为id类型;
                 若为“v@:”表示返回值为void,第一个参数为id类型,:表示@selector(_cmd)
            
        (B)然后定义函数
        static void addMethodForMyClass(id self, SEL _cmd, NSString *test) {
           // 获取类中指定名称实例成员变量的信息
              Ivar ivar = class_getInstanceVariable([self class], "test");
           // 返回名为test的ivar变量的值
           id obj = object_getIvar(self, ivar);
            NSLog(@"%@",obj);
            NSLog(@"addMethodForMyClass:参数:%@",test);
            NSLog(@"ClassName:%@",NSStringFromClass([self class]));
        }

      (C)定义OC的方法
        //这个方法实际上没有被调用,但是必须实现否则不会调用addMethodForMyClass()方法
        - (void)addMethodForMyClass:(NSString *)string {
        }

    <5> 实例化类对象
        OC:      id myObjc = [[MyClass alloc] init];
        runtime:id myobjc = objc_msgSend(MyClass, @selector(alloc));
               myobjc = objc_msgSend(myobjc, @selector(init)); 

    <6> 给动态添加的属性赋值
        // 通过KVC的方式给myObj对象的test属性赋值
      [myobjc setValue:@“wang” forKey:@"test"]; 

     <7> 调用动态添加的方法
        // 如果不调用- (void)addMethodForMyClass:(NSString )string 这个方法,
             就不会调用static void addMethodForMyClass(id self, SEL _cmd, NSString test) 函数
        [myobjc addMethodForMyClass:@"参数"];

     <8> 遍历一个类的所有成员变量(属性)\所有方法 (在归档中使用很方便)
        - (void)encodeWithCoder:(NSCoder *)encoder { 
                unsigned int count = 0;
                Ivar *ivars = class_copyIvarList([PYPerson class], &count);
             for (int i = 0; i<count; i++) { 
                // 取出i位置对应的成员变量 
                Ivar ivar = ivars[i];
                // 获取成员变量的名称的C字符串
                const char * name = ivar_getName(ivar);
                // 归档
                NSString *key = [NSString stringWithUTF8String:name];
                id  value  = [self  valueForKey:key];
                [encoder  encodeObject:value  ForKey:key];
            }
            free(ivars);
        }

        -(id)initWithCoder:(NSCoder *)aDecoder 
        { 
            if (self = [super init]) {
                 unsigned int count = 0; 
                 Ivar *ivars = class_copyIvarList([PYPerson class], &count);
                for(int i=0;i<count;i++) {
                    // 通过下标取出成员变量
                    Ivar ivar = ivars[i];
                    // 获取成员变量的名称的C字符串
                    const char * name = ivar_getName(ivar);
                    // 归档
                    NSString *key = [NSString stringWithUTF8String:name];
                    id  value  = [aDecoder  decodeObjectForKey:key];
                    [self setValue:value forKey:key];
                }
                free(ivars);
            }
            return  self;
        }

相关文章

网友评论

      本文标题:ios -- 知识点

      本文链接:https://www.haomeiwen.com/subject/zeddmxtx.html