数据库中left join,right join,inner join的出入

 

老三着框架

  1. AFNetworking
    底层原理分析

    AFNetworking主要是对NSURLSession和NSURLConnection(iOS9.0废弃)的封装,其中主要有以下类:
    1). AFHTTPRequestOperationManager:内部封装的是 NSURLConnection, 负责发送网络请求, 使用最多的一个类。(3.0废弃)
    2). AFHTTPSessionManager:内部封装是 NSURLSession, 负责发送网络请求,使用最多的一个类。
    3). AFNetworkReachabilityManager:实时监测网络状态的工具类。当前的网络环境发生改变之后,这个工具类就可以检测到。
    4). AFSecurityPolicy:网络安全的工具类, 主要是针对 HTTPS 服务。
    
    5). AFURLRequestSerialization:序列化工具类,基类。上传的数据转换成JSON格式
        (AFJSONRequestSerializer).使用不多。
    6). AFURLResponseSerialization:反序列化工具类;基类.使用比较多:
    7). AFJSONResponseSerializer; JSON解析器,默认的解析器.
    8). AFHTTPResponseSerializer; 万能解析器; JSON和XML之外的数据类型,直接返回二进
    制数据.对服务器返回的数据不做任何处理.
    9). AFXMLParserResponseSerializer; XML解析器;
    
  2. 叙述下SDWebImage里面给UIImageView加载图片的逻辑

    SDWebImage 中为 UIImageView 提供了一个分类UIImageView+WebCache.h, 这个分类中有一个最常用的接口sd_setImageWithURL:placeholderImage:,会在真实图片出现前会先显示占位图片,当真实图片被加载出来后再替换占位图片。
    
    加载图片的过程大致如下:
        1.首先会在 SDWebImageCache 中寻找图片是否有对应的缓存, 它会以url 作为数据的索引先在内存中寻找是否有对应的缓存
        2.如果缓存未找到就会利用通过MD5处理过的key来继续在磁盘中查询对应的数据, 如果找到了, 就会把磁盘中的数据加载到内存中,并将图片显示出来
        3.如果在内存和磁盘缓存中都没有找到,就会向远程服务器发送请求,开始下载图片
        4.下载后的图片会加入缓存中,并写入磁盘中
        5.整个获取图片的过程都是在子线程中执行,获取到图片后回到主线程将图片显示出来
    
    SDWebImage原理:
    调用类别的方法:
        1. 从内存(字典)中找图片(当这个图片在本次使用程序的过程中已经被加载过),找到直接使用。
        2. 从沙盒中找(当这个图片在之前使用程序的过程中被加载过),找到使用,缓存到内存中。
        3. 从网络上获取,使用,缓存到内存,缓存到沙盒。
    
  3. 友盟统计接口统计的拥有功能

    APP启动速度,APP停留页面时间等
    

3,全连接Full join

要中之一表存在相当,FULL JOIN
关键字就算见面回回行。

FULL JOIN 关键字语法

SELECT column_name(s)

FROM table_name1

FULL JOIN table_name2

ON table_name1.column_name=table_name2.column_name

 

下列有了当时几乎单好行使的 JOIN
类型,以及它中的距离。

  • JOIN: 如果表中发生至少一个相当,则赶回回行
  • LEFT JOIN: 即使右表中并未匹配,也打左表返回所有的行
  • RIGHT JOIN: 即使左表中无匹配,也打右表返回所有的施行
  • FULL JOIN: 只要其中一个表中存在相当,就回来回行

 

 

 

 

 多余:

老三说明联结查询

select username,psw,gname,tel from (t1 left join t2 on
t1.t1_id=t2.t1_id) left join t3 on t1.t1_id=t3.t1_id

 

其三个说明信息:

tems:商品表,item_visit_stats:商品访问表,item_trade_stats:商品销售表

 

SELECT i.num_iid, i.title, i.price, SUM(iv.user_visits) AS
uv,it.buyer_num,it.item_num,it.item_num*i.price AS turnover
FROM (

items AS i RIGHT JOIN item_visit_stats AS iv ON
i.num_iid=iv.num_iid)
LEFT JOIN (

SELECT num_iid,SUM(buyer_num) AS buyer_num,SUM(item_num) AS
item_num FROM item_trade_stats
WHERE seller_nick=”XXXX” AND business_day BETWEEN ‘2017-08-14’ AND
‘2017-08-15’ GROUP BY num_iid)
AS it ON it.num_iid=iv.num_iid 
WHERE i.nick=”XXXX” AND iv.business_day BETWEEN ‘2017-08-14’ AND
‘2017-08-15’
GROUP BY i.num_iid ORDER BY uv DESC

 

别知识点

  1. HomeKit,是苹果2014年宣告的智能家居平台。

  2. 什么是 OpenGL、Quartz
    2D?

    Quatarz 2d 是Apple提供的基本图形工具库。只是适用于2D图形的绘制。
    OpenGL,是一个跨平台的图形开发库。适用于2D和3D图形的绘制。
    
  3. ffmpeg框架:​ffmpeg
    是音视频处理工具,既出音视频编码解码功能,又可以当做播放器使用。

  1. 谈谈 UITableView
    的优化

    1). 正确的复用cell。
    2). 设计统一规格的Cell
    3). 提前计算并缓存好高度(布局),因为heightForRowAtIndexPath:是调用最频繁的方法;
    4). 异步绘制,遇到复杂界面,遇到性能瓶颈时,可能就是突破口;
    4). 滑动时按需加载,这个在大量图片展示,网络加载的时候很管用!
    5). 减少子视图的层级关系
    6). 尽量使所有的视图不透明化以及做切圆操作。
    7). 不要动态的add 或者 remove 子控件。最好在初始化时就添加完,然后通过hidden来控制是否显示。
    8). 使用调试工具分析问题。
    
  2. 怎么履行cell的动态的行高

    如果希望每条数据显示自身的行高,必须设置两个属性,1.预估行高,2.自定义行高。
    设置预估行高 tableView.estimatedRowHeight = 200。
    设置定义行高 tableView.estimatedRowHeight = UITableViewAutomaticDimension。 
    如果要让自定义行高有效,必须让容器视图有一个自下而上的约束。
    
  3. 说说您针对 block
    的明白

    栈上的自动复制到堆上,block 的属性修饰符是 copy,循环引用的原理和解决方案。
    
  4. 说说公针对 runtime
    的明亮

    主要是方法调用时如何查找缓存,如何找到方法,找不到方法时怎么转发,对象的内存布局。
    
  5. 哎是野指针、空指针?

    野指针:不知道指向了哪里的指针叫野指针。即指针指向不确定,指针存的地址是一个垃圾值,未初始化。
    空指针:不指向任何位置的指针叫空指针。即指针没有指向,指针存的地址是一个空地址,NULL。
    
  6. 什么是 OOA / OOD / OOP ?

    OOA(Object Oriented Analysis)   --面向对象分析
    OOD(Object Oriented Design)     --面向对象设计
    OOP(Object Oriented Programming)--面向对象编程
    

     

on、where、having的区别

 
 on、where、having这三个还可以加以条件的子句中,on是状元执行,where次之,having最后。有时候要当时先后顺序不影响中结果的言语,那最终结果是同样之。

 
但因为on是优先把不符合条件的笔录过滤后才开展统计,它就足以减小中间运算而拍卖的数据,按理说应该速度是极度抢的。
      

  
在个别单表联接时才用on的,所以在一个发明底时刻,就剩下where跟having比较了。在及时单表查询统计的情景下,如果要是过滤的规格尚未干到如果计算字段,那她的结果是千篇一律的。  
  
如果如提到到计算的字段,就表示以没算之前,这个字段的价值是无确定的,根据达篇写的办事流程,where的意时间是当测算之前便做到的,而having就是于盘算后才由作用的,所以在这种状态下,两者的结果会不同。     
  
以多表联接查询时,on比where更早由作用。系统率先冲各国个表之间的接入条件,把多只表合成一个临时表后,再由where进行过滤,然后重新计,计算完后重新由having进行过滤。

 
由此可见,要想过滤条件由及对的来意,首先使知道这个标准应该在啊时打作用,然后又决定在那里
 

 

 

 

规范的模版

select * from (

select 表A.*,表B.*

from 表A  left join 表B on 表A.x=表B.x )

where 表A.y<>表B.y or 表B.x is null;

 

left join是盖A表的笔录也底蕴之,A可以当做左表,B可以当作右表,left
join是以左表为仍的。

转移句话说,左表(A)的笔录将会晤尽代表出,而右表(B)只会显示符合查找条件的记录(例子中也:
A.aID = B.bID)。B表记录不足的地方全为NULL。

 

right join右连接A、B表的结果跟左连接B、A的结果是如出一辙的,返回包括右表中之兼具记录和左表中集合字段相等的笔录。也就是说:

Select A.name,B.name from B Right Join A on
B.id-A.id执行后的结果是一律的。

RIGHT JOIN 关键字会右表 (table_name2) 那里回来所有的实施,即使以左表
(table_name1) 中尚无匹配的尽。

RIGHT JOIN 关键字语法

SELECT column_name(s)

FROM table_name1

RIGHT JOIN table_name2

ON table_name1.column_name=table_name2.column_name

 

一个误区:

相思查询B表中的保有type为1之数,A表中得知有字段加入到B结果吃。

比较下下两句子SQL

1.select * from A right join B on B.type=1 where A.id=B.aid;

2.select * from B left join A on A.id=B.aid where B.type=1 ;

自原来是准第一句写的,结果出来时,我觉得老奇怪。为什么right
join,不可知把右表里type为1之多少总体抱出来。

 

首先句子,先实施on部分,查出了所有B的数目,然后跟A进行右连接,最后根据标准A.id=B.aid,筛选数据,这样只要无满足A.id=B.aid的数据,将会晤于结果中失去除,包括B的数!

亚句,先实行on部分,查出A中装有满足A.id=B.aid的多少,再展开不当连接,最后因type=1做筛选。

足见,第二句子sql才是正确的法子。

 

 

算法

  1. 绝不中间变量,用少种办法交换A和B的值

    // 1.中间变量
    void swap(int a, int b) {
       int temp = a;
       a = b;
       b = temp;
    }
    
    // 2.加法
    void swap(int a, int b) {
       a = a + b;
       b = a - b;
       a = a - b;
    }
    
    // 3.异或(相同为0,不同为1. 可以理解为不进位加法)
    void swap(int a, int b) {
       a = a ^ b;
       b = a ^ b;
       a = a ^ b;
    }
    

  2. 请求最大公约数

    /** 1.直接遍历法 */
    int maxCommonDivisor(int a, int b) {
        int max = 0;
        for (int i = 1; i <=b; i++) {
            if (a % i == 0 && b % i == 0) {
                max = i;
            }
        }
        return max;
    }
    /** 2.辗转相除法 */
    int maxCommonDivisor(int a, int b) {
        int r;
        while(a % b > 0) {
            r = a % b;
            a = b;
            b = r;
        }
        return b;
    }
    
    // 扩展:最小公倍数 = (a * b)/最大公约数
    
  3. 模拟栈操作

     /**
     *  栈是一种数据结构,特点:先进后出
     *  练习:使用全局变量模拟栈的操作
     */
    #include <stdio.h>
    #include <stdbool.h>
    #include <assert.h>
    //保护全局变量:在全局变量前加static后,这个全局变量就只能在本文件中使用
    static int data[1024];//栈最多能保存1024个数据
    static int count = 0;//目前已经放了多少个数(相当于栈顶位置)
    
    //数据入栈 push
    void push(int x){
        assert(!full());//防止数组越界
        data[count++] = x;
    }
    //数据出栈 pop
    int pop(){
        assert(!empty());
        return data[--count];
    }
    //查看栈顶元素 top
    int top(){
        assert(!empty());
        return data[count-1];
    }
    
    //查询栈满 full
    bool full() {
        if(count >= 1024) {
            return 1;
        }
         return 0; 
    }
    
    //查询栈空 empty
    bool empty() {
        if(count <= 0) {
            return 1;
        }
        return 0;
    }
    
    int main(){
        //入栈
        for (int i = 1; i <= 10; i++) {
            push(i);
        }
    
        //出栈
        while(!empty()){
            printf("%d ", top()); //栈顶元素
            pop(); //出栈
        }
        printf("\n");
        
        return 0;
    }
    
  4. 排序算法

    选取排序、冒泡排序、插入排序三栽排序算法可以总结为如下:

    • 且将数组分为已排序有和未破序部分。

      1. 选择排序将已排序部分定义在左端,然后选择未排序部分的最小元素和未排序部分的第一个元素交换。
      2. 冒泡排序将已排序部分定义在右端,在遍历未排序部分的过程执行交换,将最大元素交换到最右端。
      3. 插入排序将已排序部分定义在左端,将未排序部分元的第一个元素插入到已排序部分合适的位置。
      
    • 慎选排序

    /** 
     *  【选择排序】:最值出现在起始端
     *  
     *  第1趟:在n个数中找到最小(大)数与第一个数交换位置
     *  第2趟:在剩下n-1个数中找到最小(大)数与第二个数交换位置
     *  重复这样的操作...依次与第三个、第四个...数交换位置
     *  第n-1趟,最终可实现数据的升序(降序)排列。
     *
     */
    void selectSort(int *arr, int length) {
        for (int i = 0; i < length - 1; i++) { //趟数
            for (int j = i + 1; j < length; j++) { //比较次数
                if (arr[i] > arr[j]) {
                    int temp = arr[i];
                    arr[i] = arr[j];
                    arr[j] = temp;
                }
            }
        }
    }
    
    • 冒泡排序

    /** 
     *  【冒泡排序】:相邻元素两两比较,比较完一趟,最值出现在末尾
     *  第1趟:依次比较相邻的两个数,不断交换(小数放前,大数放后)逐个推进,最值最后出现在第n个元素位置
     *  第2趟:依次比较相邻的两个数,不断交换(小数放前,大数放后)逐个推进,最值最后出现在第n-1个元素位置
     *   ……   ……
     *  第n-1趟:依次比较相邻的两个数,不断交换(小数放前,大数放后)逐个推进,最值最后出现在第2个元素位置    
     */
    void bublleSort(int *arr, int length) {
        for(int i = 0; i < length - 1; i++) { //趟数
            for(int j = 0; j < length - i - 1; j++) { //比较次数
                if(arr[j] > arr[j+1]) {
                    int temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            } 
        }
    }
    
  5. 亏本半物色(二分割查找)

    /**
     *  折半查找:优化查找时间(不用遍历全部数据)
     *
     *  折半查找的原理:
     *   1> 数组必须是有序的
     *   2> 必须已知min和max(知道范围)
     *   3> 动态计算mid的值,取出mid对应的值进行比较
     *   4> 如果mid对应的值大于要查找的值,那么max要变小为mid-1
     *   5> 如果mid对应的值小于要查找的值,那么min要变大为mid+1
     *
     */ 
    
    // 已知一个有序数组, 和一个key, 要求从数组中找到key对应的索引位置 
    int findKey(int *arr, int length, int key) {
        int min = 0, max = length - 1, mid;
        while (min <= max) {
            mid = (min + max) / 2; //计算中间值
            if (key > arr[mid]) {
                min = mid + 1;
            } else if (key < arr[mid]) {
                max = mid - 1;
            } else {
                return mid;
            }
        }
        return -1;
    }
    

编码格式(优化细节)

  1. 当 Objective-C 中,enum 建议以
    NS_ENUMNS_OPTIONS 宏来定义枚举类型。

    //定义一个枚举(比较严密)
    typedef NS_ENUM(NSInteger, BRUserGender) {
        BRUserGenderUnknown,    // 未知
        BRUserGenderMale,       // 男性
        BRUserGenderFemale,     // 女性
        BRUserGenderNeuter      // 无性
    };
    
    @interface BRUser : NSObject<NSCopying>
    
    @property (nonatomic, readonly, copy) NSString *name;
    @property (nonatomic, readonly, assign) NSUInteger age;
    @property (nonatomic, readonly, assign) BRUserGender gender;
    
    - (instancetype)initWithName:(NSString *)name age:(NSUInteger)age gender:(BRUserGender)gender;
    
    @end
    
    //说明:
    //既然该类中已经有一个“初始化方法” ,用于设置 name、age 和 gender 的初始值: 那么在设计对应 @property 时就应该尽量使用不可变的对象:其三个属性都应该设为“只读”。用初始化方法设置好属性值之后,就不能再改变了。
    //属性的参数应该按照下面的顺序排列: (原子性,读写,内存管理)
    

  2. 免采取C语言中的中心数据列,建议利用
    Foundation 数据类型,对承诺涉及如下:

    int -> NSInteger
    unsigned -> NSUInteger
    float -> CGFloat
    动画时间 -> NSTimeInterval
    

1、外连接(等值连接)

以少单说明中在属关系之字段符合连接条件的笔录形成记录集。只回两单说明中集合字段相等的履

Select A.name,B.name from A inner join B on A.id=B.id和

Select A.name,B.name from A,B where
A.id=B.id结果是相同的(内接连的inner关键字而粗略);

以表中设有至少一个郎才女貌时,INNER
JOIN 关键字返回行。

INNER JOIN 关键字语法

SELECT column_name(s)

FROM table_name1

INNER JOIN table_name2

ON table_name1.column_name=table_name2.column_name

 

2、外接连:分为左外连接和右外连接

left join左连接A、B表结果连A的全体笔录以及符合条件的B的记录。返回包括左表中之兼具记录及右表中集合字段相等的笔录。

Select A.name,B.name from A Left Join B on A.id=B.id

里LEFT JOIN 关键字会从左表
(table_name1) 那里回来所有的行,即使以右表 (table_name2)
中没有匹配的履行。

LEFT JOIN 关键字语法

SELECT column_name(s)

FROM table_name1

LEFT JOIN table_name2

ON table_name1.column_name=table_name2.column_name

连续通常可以于select语句之from子句或where子句被成立,其语法格式为:

select colunm_name1,colunm_name2

from table_name1

left join table_name2

on table_name1.colunmname=table_name2.colunmname

其中join_table指出与连接操作的表名,连接可以对同一个表操作,也堪对多表操作,对同一个表操作的连日称为自连接,
join_type 为连日来路,可以是left join 或者right join 或者inner join 。

 

left join与where共同以

select a.*,b.*

from table1 a

left join table2 b on b.X=a.X

where XXX

倘达到:一旦用了left
join,没有where条件时,左表table1会显示全部内容。使用了where,只有满足where条件的记录才见面显示(左表显示有或全部无亮)

so。。。。

left join的困惑:一旦增长where条件,则显示的结果当inner join 

 

因剖析:

数据库在经过连续两摆放或多张表来回到记录时,都见面老成一摆中间的临时表,然后再以及时张临时表返回给用户;

where条件是于现表生成好后,再指向临时表进行过滤的基准;

用:where
条件丰富,已经没left
join的含义(必须返回左边表的记录)了,条件不也真正就是举过滤掉。 

 

缓解方案:

1、where过滤结果作为子查询,和主表left,如下:

select a.*,tmp.*from table1 aleft join(

    select a.*,b.*

    from table1 a

    left join table2 b on b.X=a.X

    where XXX

)tmp

很明白,子查询语句无论 left
join、inner join都没啥区别了

2、查询条件在on后面

select a.*,b.*

from table1 a

left join table2  b

       on b.X=a.X and XXX

注意:where XXX去丢,改吧链接条件on后面的
and XXX

分析:on条件是于变临时表时使用的规则,它不管on中之规范是否也实在,都见面回左边表中的笔录。

结论:过滤条件在:

where后面:是事先连接然生成临时查询结果,然后再筛选。

on后面:先根据条件过滤筛选,再连 生成临时查询结果。

对此left
join,不管on后面和什么法,左表的数总体翻出来,因此而想了滤需将准放到where后面

于inner
join,满足on后面的尺度表的数量才会识破,可以打至过滤作用。也可拿尺度放到where后面。

 

  1. 设计模式是啊?
    你知道哪些设计模式,并简短叙述?

    设计模式是一种编码经验,就是用比较成熟的逻辑去处理某一种类型的事情。
    1). MVC模式:Model View Control,把模型 视图 控制器 层进行解耦合编写。
    2). MVVM模式:Model View ViewModel 把模型 视图 业务逻辑 层进行解耦和编写。
    3). 单例模式:通过static关键词,声明全局变量。在整个进程运行期间只会被赋值一次。
    4). 观察者模式:KVO是典型的通知模式,观察某个属性的状态,状态发生变化时通知观察者。
    5). 委托模式:代理+协议的组合。实现1对1的反向传值操作。
    6). 工厂模式:通过一个类方法,批量的根据已有模板生产对象。
    
  2. MVC 和 MVVM 的区别

    1). MVVM是对胖模型进行的拆分,其本质是给控制器减负,将一些弱业务逻辑放到VM中去处理。
    2). MVC是一切设计的基础,所有新的设计模式都是基于MVC进行的改进。
    
  3. #import跟 #include
    有什么分别,@class呢,#import<> 跟
    #import””有什么区别?

    答:
    1). #import是Objective-C导入头文件的关键字,#include是C/C++导入头文件的关键字,使用#import头文件会自动只导入一次,不会重复导入。
    2). @class告诉编译器某个类的声明,当执行时,才去查看类的实现文件,可以解决头文件的相互包含。
    3). #import<>用来包含系统的头文件,#import””用来包含用户头文件。
    
  4. frame 和 bounds
    有什么不同?

    frame指的是:该view在父view坐标系统中的位置和大小。(参照点是父view的坐标系统)
    bounds指的是:该view在本身坐标系统中的位置和大小。(参照点是本身坐标系统)
    
  5. Objective-C的好像可多重继承么?可以兑现多独接入口么?Category是什么?重写一个好像的方法因此连续好要分类好?为什么?

    答:Objective-C的类不可以多重继承;可以实现多个接口(协议);Category是类别;一般情况用分类好,用Category去重写类的方法,仅对本Category有效,不会影响到其他类与原有类的关系。
    
  6. @property
    的原形是什么?ivar、getter、setter
    是怎么转移并加加至是看似吃的

    @property 的本质是什么?
        @property = ivar + getter + setter;
    “属性” (property)有两大概念:ivar(实例变量)、getter+setter(存取方法)
    
    “属性” (property)作为 Objective-C 的一项特性,主要的作用就在于封装对象中的数据。 Objective-C 对象通常会把其所需要的数据保存为各种实例变量。实例变量一般通过“存取方法”(access method)来访问。其中,“获取方法” (getter)用于读取变量值,而“设置方法” (setter)用于写入变量值。
    
  7. @property中发出怎么样性关键字?/
    @property 后面可以起哪修饰符?

    属性可以拥有的特质分为四类:
    1.原子性--- nonatomic 特质
    2.读/写权限---readwrite(读写)、readonly (只读)
    3.内存管理语义---assign、strong、 weak、unsafe_unretained、copy
    4.方法名---getter=<name> 、setter=<name>
    5.不常用的:nonnull,null_resettable,nullable
    
  8. 属性关键字
    readwrite,readonly,assign,retain,copy,nonatomic
    各是呀作用,在那种情况下用?

    答:
    1). readwrite 是可读可写特性。需要生成getter方法和setter方法。
    2). readonly 是只读特性。只会生成getter方法,不会生成setter方法,不希望属性在类外改变。
    3). assign 是赋值特性。setter方法将传入参数赋值给实例变量;仅设置变量时,assign用于基本数据类型。
    4). retain(MRC)/strong(ARC) 表示持有特性。setter方法将传入参数先保留,再赋值,传入参数的retaincount会+1。
    5). copy 表示拷贝特性。setter方法将传入对象复制一份,需要完全一份新的变量时。
    6). nonatomic 非原子操作。决定编译器生成的setter和getter方法是否是原子操作,atomic表示多线程安全,一般使用nonatomic,效率高。
    
  9. 什么动静使用 weak 关键字,相比
    assign 有啊不同?

    1.在 ARC 中,在有可能出现循环引用的时候,往往要通过让其中一端使用 weak 来解决,比如: delegate 代理属性。
    2.自身已经对它进行一次强引用,没有必要再强引用一次,此时也会使用 weak,自定义 IBOutlet 控件属性一般也使用 weak;当然,也可以使用strong。
    
    IBOutlet连出来的视图属性为什么可以被设置成weak?
        因为父控件的subViews数组已经对它有一个强引用。
    
    不同点:
    assign 可以用非 OC 对象,而 weak 必须用于 OC 对象。
    weak 表明该属性定义了一种“非拥有关系”。在属性所指的对象销毁时,属性值会自动清空(nil)。
    
  10. 怎么用 copy 关键字?

     用途:
     1. NSString、NSArray、NSDictionary 等等经常使用copy关键字,是因为他们有对应的可变类型:NSMutableString、NSMutableArray、NSMutableDictionary;
     2. block 也经常使用 copy 关键字。
    
     说明:
     block 使用 copy 是从 MRC 遗留下来的“传统”,在 MRC 中,方法内部的 block 是在栈区的,使用 copy 可以把它放到堆区.在 ARC 中写不写都行:对于 block 使用 copy 还是 strong 效果是一样的,但写上 copy 也无伤大雅,还能时刻提醒我们:编译器自动对 block 进行了 copy 操作。如果不写 copy ,该类的调用者有可能会忘记或者根本不知道“编译器会自动对 block 进行了 copy 操作”,他们有可能会在调用之前自行拷贝属性值。这种操作多余而低效。
    
  11. 故此@property声明的 NSString /
    NSArray / NSDictionary 经常使用 copy
    关键字,为什么?如果改用strong关键字,可能引致什么问题?

    答:用 @property 声明 NSString、NSArray、NSDictionary 经常使用 copy 关键字,是因为他们有对应的可变类型:NSMutableString、NSMutableArray、NSMutableDictionary,他们之间可能进行赋值操作(就是把可变的赋值给不可变的),为确保对象中的字符串值不会无意间变动,应该在设置新属性值时拷贝一份。
    
    1. 因为父类指针可以指向子类对象,使用 copy 的目的是为了让本对象的属性不受外界影响,使用 copy 无论给我传入是一个可变对象还是不可对象,我本身持有的就是一个不可变的副本。
    2. 如果我们使用是 strong ,那么这个属性就有可能指向一个可变对象,如果这个可变对象在外部被修改了,那么会影响该属性。
    
    //总结:使用copy的目的是,防止把可变类型的对象赋值给不可变类型的对象时,可变类型对象的值发送变化会无意间篡改不可变类型对象原来的值。
    
  12. 浅拷贝和深拷贝的界别?

    答:
    浅拷贝:只复制指向对象的指针,而不复制引用对象本身。
    深拷贝:复制引用对象本身。内存中存在了两份独立对象本身,当修改A时,A_copy不变。
    
  13. 系统对象的 copy 与 mutableCopy
    方法

    不管是集合类对象(NSArray、NSDictionary、NSSet ... 之类的对象),还是非集合类对象(NSString, NSNumber ... 之类的对象),接收到copy和mutableCopy消息时,都遵循以下准则:
    1. copy 返回的是不可变对象(immutableObject);如果用copy返回值调用mutable对象的方法就会crash。
    2. mutableCopy 返回的是可变对象(mutableObject)。
    
    一、非集合类对象的copy与mutableCopy
      在非集合类对象中,对不可变对象进行copy操作,是指针复制,mutableCopy操作是内容复制;
      对可变对象进行copy和mutableCopy都是内容复制。用代码简单表示如下:
        NSString *str = @"hello word!";
        NSString *strCopy = [str copy] // 指针复制,strCopy与str的地址一样
        NSMutableString *strMCopy = [str mutableCopy] // 内容复制,strMCopy与str的地址不一样
    
        NSMutableString *mutableStr = [NSMutableString stringWithString: @"hello word!"];
        NSString *strCopy = [mutableStr copy] // 内容复制
        NSMutableString *strMCopy = [mutableStr mutableCopy] // 内容复制
    
    二、集合类对象的copy与mutableCopy (同上)
      在集合类对象中,对不可变对象进行copy操作,是指针复制,mutableCopy操作是内容复制;
      对可变对象进行copy和mutableCopy都是内容复制。但是:集合对象的内容复制仅限于对象本身,对集合内的对象元素仍然是指针复制。(即单层内容复制)
        NSArray *arr = @[@[@"a", @"b"], @[@"c", @"d"];
        NSArray *copyArr = [arr copy]; // 指针复制
        NSMutableArray *mCopyArr = [arr mutableCopy]; //单层内容复制
    
        NSMutableArray *array = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil];
        NSArray *copyArr = [mutableArr copy]; // 单层内容复制
        NSMutableArray *mCopyArr = [mutableArr mutableCopy]; // 单层内容复制
    
    【总结一句话】:
        只有对不可变对象进行copy操作是指针复制(浅复制),其它情况都是内容复制(深复制)!
    
  14. 夫写法会时有发生什么问题:@property
    (nonatomic, copy) NSMutableArray \
    arr;*

    问题:添加,删除,修改数组内的元素的时候,程序会因为找不到对应的方法而崩溃。
    //如:-[__NSArrayI removeObjectAtIndex:]: unrecognized selector sent to instance 0x7fcd1bc30460
    // copy后返回的是不可变对象(即 arr 是 NSArray 类型,NSArray 类型对象不能调用 NSMutableArray 类型对象的方法)
    原因:是因为 copy 就是复制一个不可变 NSArray 的对象,不能对 NSArray 对象进行添加/修改。
    
  15. 何以让自己的类用 copy
    修饰符?如何还写带 copy 关键字的 setter?

    若想令自己所写的对象具有拷贝功能,则需实现 NSCopying 协议。如果自定义的对象分为可变版本与不可变版本,那么就要同时实现 NSCopying 与 NSMutableCopying 协议。
    具体步骤:
        1. 需声明该类遵从 NSCopying 协议
        2. 实现 NSCopying 协议的方法。
            // 该协议只有一个方法: 
            - (id)copyWithZone:(NSZone *)zone;
            // 注意:使用 copy 修饰符,调用的是copy方法,其实真正需要实现的是 “copyWithZone” 方法。
    
  16. 写一个 setter 方法用于完成
    @property (nonatomic, retain) NSString \
    name,写一个 setter
    方法用于完成 @property (nonatomic, copy) NSString *name*

    答:
    // retain
    - (void)setName:(NSString *)str {
      [str retain];
      [_name release];
      _name = str;
    }
    // copy
    - (void)setName:(NSString *)str {
      id t = [str copy];
      [_name release];
      _name = t;
    }
    
  17. @synthesize 和 @dynamic
    分别产生什么打算?

    @property有两个对应的词,一个是@synthesize(合成实例变量),一个是@dynamic。
    如果@synthesize和@dynamic都没有写,那么默认的就是 @synthesize var = _var;
    // 在类的实现代码里通过 @synthesize 语法可以来指定实例变量的名字。(@synthesize var = _newVar;)
    1. @synthesize 的语义是如果你没有手动实现setter方法和getter方法,那么编译器会自动为你加上这两个方法。
    2. @dynamic 告诉编译器,属性的setter与getter方法由用户自己实现,不自动生成(如,@dynamic var)。
    
  18. 泛的 Objective-C
    的数据类型有那些,和C的骨干数据列有什么分别?如:NSInteger和int

    答:
    Objective-C的数据类型有NSString,NSNumber,NSArray,NSMutableArray,NSData等等,这些都是class,创建后便是对象,而C语言的基本数据类型int,只是一定字节的内存空间,用于存放数值;NSInteger是基本数据类型,并不是NSNumber的子类,当然也不是NSObject的子类。NSInteger是基本数据类型Int或者Long的别名(NSInteger的定义typedef long NSInteger),它的区别在于,NSInteger会根据系统是32位还是64位来决定是本身是int还是long。
    
  19. id
    声明的目标有什么特点?

    答:id 声明的对象具有运行时的特性,即可以指向任意类型的Objcetive-C的对象。
    
  20. Objective-C
    如何对内存管理的,说说您的见以及解决措施?

    答:Objective-C的内存管理主要有三种方式ARC(自动内存计数)、手动内存计数、内存池。
    1). 自动内存计数ARC:由Xcode自动在App编译阶段,在代码中添加内存管理代码。
    2). 手动内存计数MRC:遵循内存谁申请、谁释放;谁添加,谁释放的原则。
    3). 内存释放池Release Pool:把需要释放的内存统一放在一个池子中,当池子被抽干后(drain),池子中所有的内存空间也被自动释放掉。内存池的释放操作分为自动和手动。自动释放受runloop机制影响。
    
  21. Objective-C
    中开创线程的方是啊?如果以主线程遭遇实施代码,方法是啊?如果想延时执行代码、方法以是什么?

    答:线程创建有三种方法:使用NSThread创建、使用GCD的dispatch、使用子类化的NSOperation,然后将其加入NSOperationQueue;在主线程执行代码,方法是performSelectorOnMainThread,如果想延时执行代码可以用performSelector:onThread:withObject:waitUntilDone:
    
  22. Category(类别)、
    Extension(扩展)和连续的分

    区别:
    1. 分类有名字,类扩展没有分类名字,是一种特殊的分类。
    2. 分类只能扩展方法(属性仅仅是声明,并没真正实现),类扩展可以扩展属性、成员变量和方法。
    3. 继承可以增加,修改或者删除方法,并且可以增加属性。
    
  23. 咱们说的OC是动态运行时语言是什么意思?

    答:主要是将数据类型的确定由编译时,推迟到了运行时。简单来说, 运行时机制使我们直到运行时才去决定一个对象的类别,以及调用该类别对象指定方法。
    
  24. 干什么我们广阔的delegate属性都为此是week而无是retain/strong?

    答:是为了防止delegate两端产生不必要的循环引用。
    @property (nonatomic, weak) id<UITableViewDelegate> delegate;
    
  25. 咦时用delete,什么时用Notification?

    Delegate(委托模式):1对1的反向消息通知功能。
    Notification(通知模式):只想要把消息发送出去,告知某些状态的变化。但是并不关心谁想要知道这个。
    
  26. 什么是 KVO 和 KVC?

    1). KVC(Key-Value-Coding):键值编码 是一种通过字符串间接访问对象的方式(即给属性赋值)
        举例说明:
        stu.name = @"张三" // 点语法给属性赋值
        [stu setValue:@"张三" forKey:@"name"]; // 通过字符串使用KVC方式给属性赋值
        stu1.nameLabel.text = @"张三";
        [stu1 setValue:@"张三" forKey:@"nameLabel.text"]; // 跨层赋值
    2). KVO(key-Value-Observing):键值观察机制 他提供了观察某一属性变化的方法,极大的简化了代码。
         KVO只能被KVC触发,包括使用setValue:forKey:方法和点语法。
       // 通过下方方法为属性添加KVO观察
       - (void)addObserver:(NSObject *)observer
                         forKeyPath:(NSString *)keyPath
                         options:(NSKeyValueObservingOptions)options
                         context:(nullable void *)context;
       // 当被观察的属性发送变化时,会自动触发下方方法                   
       - (void)observeValueForKeyPath:(NSString *)keyPath
                                  ofObject:(id)object
                                      change:(NSDictionary *)change
                                     context:(void *)context{}
    
    KVC 和 KVO 的 keyPath 可以是属性、实例变量、成员变量。
    
  27. KVC的底部实现?

    当一个对象调用setValue方法时,方法内部会做以下操作:
    1). 检查是否存在相应的key的set方法,如果存在,就调用set方法。
    2). 如果set方法不存在,就会查找与key相同名称并且带下划线的成员变量,如果有,则直接给成员变量属性赋值。
    3). 如果没有找到_key,就会查找相同名称的属性key,如果有就直接赋值。
    4). 如果还没有找到,则调用valueForUndefinedKey:和setValue:forUndefinedKey:方法。
    这些方法的默认实现都是抛出异常,我们可以根据需要重写它们。
    
  28. KVO的底色实现?

    KVO基于runtime机制实现。
    
  29. ViewController生命周期

    按照执行顺序排列:
    1. initWithCoder:通过nib文件初始化时触发。
    2. awakeFromNib:nib文件被加载的时候,会发生一个awakeFromNib的消息到nib文件中的每个对象。      
    3. loadView:开始加载视图控制器自带的view。
    4. viewDidLoad:视图控制器的view被加载完成。  
    5. viewWillAppear:视图控制器的view将要显示在window上。
    6. updateViewConstraints:视图控制器的view开始更新AutoLayout约束。
    7. viewWillLayoutSubviews:视图控制器的view将要更新内容视图的位置。
    8. viewDidLayoutSubviews:视图控制器的view已经更新视图的位置。
    9. viewDidAppear:视图控制器的view已经展示到window上。 
    10. viewWillDisappear:视图控制器的view将要从window上消失。
    11. viewDidDisappear:视图控制器的view已经从window上消失。
    
  30. 艺术和选择器有哪里不同?

    selector是一个方法的名字,方法是一个组合体,包含了名字和实现。
    
  31. 汝是不是接触了OC中之反光机制?简单且一下定义与用

    1). class反射
        通过类名的字符串形式实例化对象。
            Class class = NSClassFromString(@"student"); 
            Student *stu = [[class alloc] init];
        将类名变为字符串。
            Class class =[Student class];
            NSString *className = NSStringFromClass(class);
    2). SEL的反射
        通过方法的字符串形式实例化方法。
            SEL selector = NSSelectorFromString(@"setName");  
            [stu performSelector:selector withObject:@"Mike"];
        将方法变成字符串。
            NSStringFromSelector(@selector*(setName:));
    
  32. 调用方法发生一定量种方法:

    1). 直接通过方法名来调用。[person show];
    2). 间接的通过SEL数据来调用 SEL aaa = @selector(show); [person performSelector:aaa];  
    
  33. 安对iOS设备开展性测试?

    答: Profile-> Instruments ->Time Profiler
    
  34. 支付品种时您是怎检查内存泄露?

    1). 静态分析 analyze。
    2). instruments工具里面有个leak可以动态分析。
    
  35. 哎呀是懒加载?

    答:懒加载就是只在用到的时候才去初始化。也可以理解成延时加载。
    我觉得最好也最简单的一个例子就是tableView中图片的加载显示了, 一个延时加载, 避免内存过高,一个异步加载,避免线程堵塞提高用户体验。
    
  36. 好像变量的
    @public,@protected,@private,@package 声明各起啊意思?

    @public 任何地方都能访问;
    @protected 该类和子类中访问,是默认的;
    @private 只能在本类中访问;
    @package 本包内使用,跨包不可以。
    
  37. 嗬是称词?

    谓词就是通过NSPredicate给定的逻辑条件作为约束条件,完成对数据的筛选。
    //定义谓词对象,谓词对象中包含了过滤条件(过滤条件比较多)
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"age<%d",30];
    //使用谓词条件过滤数组中的元素,过滤之后返回查询的结果
    NSArray *array = [persons filteredArrayUsingPredicate:predicate];
    
  38. isa指针问题

    isa:是一个Class 类型的指针. 每个实例对象有个isa的指针,他指向对象的类,而Class里也有个isa的指针, 指向meteClass(元类)。元类保存了类方法的列表。当类方法被调 用时,先会从本身查找类方法的实现,如果没有,元类会向他父类查找该方法。同时注意的是:元类(meteClass)也是类,它也是对象。元类也有isa指针,它的isa指针最终指向的是一个根元类(root meteClass)。根元类的isa指针指向本身,这样形成了一个封闭的内循环。
    
  39. 哪些看并修改一个类的村办属性?

    1). 一种是通过KVC获取。
    2). 通过runtime访问并修改私有属性。
    
  40. 一个objc对象的isa的指针指于什么?有什么打算?

    答:指向他的类对象,从而可以找到对象上的方法。
    
  41. 脚的代码输出什么?

    @implementation Son : Father
    - (id)init {
       if (self = [super init]) {
           NSLog(@"%@", NSStringFromClass([self class])); // Son
           NSLog(@"%@", NSStringFromClass([super class])); // Son
       }
       return self;
    }
    @end
    // 解析:
    self 是类的隐藏参数,指向当前调用方法的这个类的实例。
    super是一个Magic Keyword,它本质是一个编译器标示符,和self是指向的同一个消息接收者。
    不同的是:super会告诉编译器,调用class这个方法时,要去父类的方法,而不是本类里的。
    上面的例子不管调用[self class]还是[super class],接受消息的对象都是当前 Son *obj 这个对象。
    
  42. 描绘一个整机的代理,包括声明、实现

    // 创建
    @protocol MyDelagate
    @required
    -(void)eat:(NSString *)foodName; 
    @optional
    -(void)run;
    @end
    
    //  声明 .h
    @interface person: NSObject<MyDelagate>
    
    @end
    
    //  实现 .m
    @implementation person
    - (void)eat:(NSString *)foodName { 
       NSLog(@"吃:%@!", foodName);
    } 
    - (void)run {
       NSLog(@"run!");
    }
    
    @end
    
  43. isKindOfClass、isMemberOfClass、selector作用分别是啊

    isKindOfClass:作用是某个对象属于某个类型或者继承自某类型。
    isMemberOfClass:某个对象确切属于某个类型。
    selector:通过方法名,获取在内存中的函数的入口地址。
    
  44. delegate 和 notification
    的区别

    1). 二者都用于传递消息,不同之处主要在于一个是一对一的,另一个是一对多的。
    2). notification通过维护一个array,实现一对多消息的转发。
    3). delegate需要两者之间必须建立联系,不然没法调用代理的方法;notification不需要两者之间有联系。
    
  45. 什么是block?

    闭包(block):闭包就是获取其它函数局部变量的匿名函数。
    
  46. block反为传值

  47. 以支配器间传值可以应用代理要block,使用block相对来说简洁。

  48. 于前头一个控制器的touchesBegan:方法外实现如下代码。

      // OneViewController.m
      TwoViewController *twoVC = [[TwoViewController alloc] init];
      twoVC.valueBlcok = ^(NSString *str) {
        NSLog(@"OneViewController拿到值:%@", str); 
      };
      [self presentViewController:twoVC animated:YES completion:nil];
    
      // TwoViewController.h   (在.h文件中声明一个block属性)
      @property (nonatomic ,strong) void(^valueBlcok)(NSString *str);
    
      // TwoViewController.m   (在.m文件中实现方法)
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
        // 传值:调用block
        if (_valueBlcok) {
            _valueBlcok(@"123456");
        }
    }
    
  49. block的小心点

    1). 在block内部使用外部指针且会造成循环引用情况下,需要用__week修饰外部指针:
        __weak typeof(self) weakSelf = self; 
    2). 在block内部如果调用了延时函数还使用弱指针会取不到该指针,因为已经被销毁了,需要在block内部再将弱指针重新强引用一下。
        __strong typeof(self) strongSelf = weakSelf;
    3). 如果需要在block内部改变外部栈区变量的话,需要在用__block修饰外部变量。
    
  50. BAD_ACCESS在啊情形下起?

    答:这种问题在开发时经常遇到。原因是访问了野指针,比如访问已经释放对象的成员变量或者发消息、死循环等。
    
  51. lldb(gdb)常用之控制台调试命令?

    1). p 输出基本类型。是打印命令,需要指定类型。是print的简写
        p (int)[[[self view] subviews] count]
    2). po 打印对象,会调用对象description方法。是print-object的简写
        po [self view]
    3). expr 可以在调试时动态执行指定表达式,并将结果打印出来。常用于在调试过程中修改变量的值。
    4). bt:打印调用堆栈,是thread backtrace的简写,加all可打印所有thread的堆栈
    5). br l:是breakpoint list的简写
    
  52. 乃相似是怎么用Instruments的?

    Instruments里面工具很多,常用:
    1). Time Profiler: 性能分析
    2). Zombies:检查是否访问了僵尸对象,但是这个工具只能从上往下检查,不智能。
    3). Allocations:用来检查内存,写算法的那批人也用这个来检查。
    4). Leaks:检查内存,看是否有内存泄露。
    
  53. iOS中常用之多寡存储方发出哪?

    数据存储有四种方案:NSUserDefault、KeyChain、file、DB。
        其中File有三种方式:plist、Archive(归档)
        DB包括:SQLite、FMDB、CoreData
    
  54. iOS的沙盒目录结构是何等的?

    沙盒结构:
    1). Application:存放程序源文件,上架前经过数字签名,上架后不可修改。
    2). Documents:常用目录,iCloud备份目录,存放数据。(这里不能存缓存文件,否则上架不被通过)
    3). Library:
            Caches:存放体积大又不需要备份的数据。(常用的缓存路径)
            Preference:设置目录,iCloud会备份设置信息。
    4). tmp:存放临时文件,不会被备份,而且这个文件下的数据有可能随时被清除的可能。
    
  55. iOS多线程技术有啊几种方式?

    答:pthread、NSThread、GCD、NSOperation
    
  56. GCD 与 NSOperation
    的区别:

    GCD 和 NSOperation 都是用于实现多线程:
        GCD 基于C语言的底层API,GCD主要与block结合使用,代码简洁高效。
        NSOperation 属于Objective-C类,是基于GCD更高一层的封装。复杂任务一般用NSOperation实现。
    
  57. 形容来用GCD方式从子线程回到主线程的计代码

    答:dispatch_sync(dispatch_get_main_queue(), ^{ });
    
  58. 怎样用GCD同步若干只异步调用?(如因若干独url异步加载多布置图,然后于都生充斥完成后合成一张整图)

    // 使用Dispatch Group追加block到Global Group Queue,这些block如果全部执行完毕,就会执行Main Dispatch Queue中的结束处理的block。
    // 创建队列组
    dispatch_group_t group = dispatch_group_create();
    // 获取全局并发队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_async(group, queue, ^{ /*加载图片1 */ });
    dispatch_group_async(group, queue, ^{ /*加载图片2 */ });
    dispatch_group_async(group, queue, ^{ /*加载图片3 */ }); 
    // 当并发队列组中的任务执行完毕后才会执行这里的代码
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            // 合并图片
    });
    
  59. dispatch_barrier_async(栅栏函数)的意是呀?

    函数定义:dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);
    作用:
        1.在它前面的任务执行结束后它才执行,它后面的任务要等它执行完成后才会开始执行。
        2.避免数据竞争
    
    // 1.创建并发队列
    dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);
    // 2.向队列中添加任务
    dispatch_async(queue, ^{  // 1.2是并行的
        NSLog(@"任务1, %@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任务2, %@",[NSThread currentThread]);
    });
    
    dispatch_barrier_async(queue, ^{
        NSLog(@"任务 barrier, %@", [NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{   // 这两个是同时执行的
        NSLog(@"任务3, %@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任务4, %@",[NSThread currentThread]);
    });
    
    // 输出结果: 任务1 任务2 ——》 任务 barrier ——》任务3 任务4 
    // 其中的任务1与任务2,任务3与任务4 由于是并行处理先后顺序不定。
    
  60. 以下代码运行结果如何?

    - (void)viewDidLoad {
        [super viewDidLoad];
        NSLog(@"1");
        dispatch_sync(dispatch_get_main_queue(), ^{
            NSLog(@"2");
        });
        NSLog(@"3");
    }
    // 只输出:1。(主线程死锁)
    
  61. 什么是 RunLoop

    从字面上讲就是运行循环,它内部就是do-while循环,在这个循环内部不断地处理各种任务。
    一个线程对应一个RunLoop,基本作用就是保持程序的持续运行,处理app中的各种事件。通过runloop,有事运行,没事就休息,可以节省cpu资源,提高程序性能。
    
    主线程的run loop默认是启动的。iOS的应用程序里面,程序启动后会有一个如下的main()函数
    int main(int argc, char * argv[]) {
        @autoreleasepool {
            return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
        }
    }
    
  62. 什么是 Runtime

    Runtime又叫运行时,是一套底层的C语言API,其为iOS内部的核心之一,我们平时编写的OC代码,底层都是基于它来实现的。
    
  63. Runtime实现之机制是呀,怎么用,一般用来干嘛?

    1). 使用时需要导入的头文件 <objc/message.h> <objc/runtime.h>
    2). Runtime 运行时机制,它是一套C语言库。
    3). 实际上我们编写的所有OC代码,最终都是转成了runtime库的东西。
        比如:
            类转成了 Runtime 库里面的结构体等数据类型,
            方法转成了 Runtime 库里面的C语言函数,
            平时调方法都是转成了 objc_msgSend 函数(所以说OC有个消息发送机制)
        // OC是动态语言,每个方法在运行时会被动态转为消息发送,即:objc_msgSend(receiver, selector)。
        // [stu show];  在objc动态编译时,会被转意为:objc_msgSend(stu, @selector(show)); 
    4). 因此,可以说 Runtime 是OC的底层实现,是OC的幕后执行者。
    
    有了Runtime库,能做什么事情呢?
     Runtime库里面包含了跟类、成员变量、方法相关的API。
     比如:
        (1)获取类里面的所有成员变量。
        (2)为类动态添加成员变量。
        (3)动态改变类的方法实现。
        (4)为类动态添加新的方法等。
     因此,有了Runtime,想怎么改就怎么改。
    
  64. 嗬是 Method
    Swizzle(黑魔法),什么状况下会下?

    1). 在没有一个类的实现源码的情况下,想改变其中一个方法的实现,除了继承它重写、和借助类别重名方法暴力抢先之外,还有更加灵活的方法 Method Swizzle。
    2). Method Swizzle 指的是改变一个已存在的选择器对应的实现的过程。OC中方法的调用能够在运行时通过改变,通过改变类的调度表中选择器到最终函数间的映射关系。
    3). 在OC中调用一个方法,其实是向一个对象发送消息,查找消息的唯一依据是selector的名字。利用OC的动态特性,可以实现在运行时偷换selector对应的方法实现。
    4). 每个类都有一个方法列表,存放着selector的名字和方法实现的映射关系。IMP有点类似函数指针,指向具体的方法实现。
    5). 我们可以利用 method_exchangeImplementations 来交换2个方法中的IMP。
    6). 我们可以利用 class_replaceMethod 来修改类。
    7). 我们可以利用 method_setImplementation 来直接设置某个方法的IMP。
    8). 归根结底,都是偷换了selector的IMP。
    
  65. _objc_msgForward
    函数是召开什么的,直接调用它用会晤生啊?

    答:_objc_msgForward是 IMP 类型,用于消息转发的:当向一个对象发送一条消息,但它并没有实现的时候,_objc_msgForward会尝试做消息转发。
    
  66. 什么是 TCP / UDP ?

    TCP:传输控制协议。
    UDP:用户数据协议。
    
    TCP 是面向连接的,建立连接需要经历三次握手,是可靠的传输层协议。
    UDP 是面向无连接的,数据传输是不可靠的,它只管发,不管收不收得到。
    简单的说,TCP注重数据安全,而UDP数据传输快点,但安全性一般。
    
  67. 通信底层原理(OSI七层模型)

    OSI采用了分层的结构化技术,共分七层:
        物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。
    
  68. 介绍一下XMPP?

    XMPP是一种以XML为基础的开放式实时通信协议。
    简单的说,XMPP就是一种协议,一种规定。就是说,在网络上传东西,XMM就是规定你上传大小的格式。
    
  69. OC中创造线程的法是呀?如果在主线程中推行代码,方法是呀?

    // 创建线程的方法
    - [NSThread detachNewThreadSelector:nil toTarget:nil withObject:nil]
    - [self performSelectorInBackground:nil withObject:nil];
    - [[NSThread alloc] initWithTarget:nil selector:nil object:nil];
    - dispatch_async(dispatch_get_global_queue(0, 0), ^{});
    - [[NSOperationQueue new] addOperation:nil];
    
    // 主线程中执行代码的方法
    - [self performSelectorOnMainThread:nil withObject:nil waitUntilDone:YES];
    - dispatch_async(dispatch_get_main_queue(), ^{});
    - [[NSOperationQueue mainQueue] addOperation:nil];
    
  70. tableView的任用机制?

    答:UITableView 通过重用单元格来达到节省内存的目的: 通过为每个单元格指定一个重用标识符,即指定了单元格的种类,当屏幕上的单元格滑出屏幕时,系统会把这个单元格添加到重用队列中,等待被重用,当有新单元格从屏幕外滑入屏幕内时,从重用队列中找看有没有可以重用的单元格,如果有,就拿过来用,如果没有就创建一个来使用。
    
  71. 故而伪代码写一个线程安全的单例模式

    static id _instance;
    + (id)allocWithZone:(struct _NSZone *)zone {
       static dispatch_once_t onceToken;
       dispatch_once(&onceToken, ^{
           _instance = [super allocWithZone:zone];
       });
       return _instance;
    }
    
    + (instancetype)sharedData {
       static dispatch_once_t onceToken;
       dispatch_once(&onceToken, ^{
           _instance = [[self alloc] init];
       });
       return _instance;
    }
    
    - (id)copyWithZone:(NSZone *)zone {
       return _instance;
    }
    
  72. 安实现视图的变形?

    答:通过修改view的 transform 属性即可。
    
  73. 以手势对象基础类UIGestureRecognizer的常用子类手势类型中哪点儿单手势来后,响应只见面履行同一次于?

    答:UITapGestureRecognizer,UISwipeGestureRecognizer是一次性手势,手势发生后,响应只会执行一次。
    
  74. 字符串常用方法:

    NSString *str = @"abc*123";
    NSArray *arr = [str componentsSeparatedByString:@"*"]; //以目标字符串把原字符串分割成两部分,存到数组中。@[@"abc", @"123"];
    
  75. 哪些高性能的被 UIImageView
    加个圆角?

    • 不好的解决方案:使用下的主意会强制Core Animation提前渲染屏幕的离屏绘制, 而离屏绘制就会给性能带来负面影响,会起卡顿的面貌出现。

      self.view.layer.cornerRadius = 5.0f;
      self.view.layer.masksToBounds = YES;
      
    • 对的化解方案:使用绘图技术

      - (UIImage *)circleImage {
          // NO代表透明
          UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0);
          // 获得上下文
          CGContextRef ctx = UIGraphicsGetCurrentContext();
          // 添加一个圆
          CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);
          CGContextAddEllipseInRect(ctx, rect);
          // 裁剪
          CGContextClip(ctx);
          // 将图片画上去
          [self drawInRect:rect];
          UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
          // 关闭上下文
          UIGraphicsEndImageContext();
          return image;
      }
      
    • 还有一样栽方案:使用了贝塞尔曲线”切割”个是图形,
      给UIImageView
      添加了底圆角,其实呢是通过绘图技术来兑现的。

      UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
      imageView.center = CGPointMake(200, 300);
      UIImage *anotherImage = [UIImage imageNamed:@"image"];
      UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, 1.0);
      [[UIBezierPath bezierPathWithRoundedRect:imageView.bounds
                             cornerRadius:50] addClip];
      [anotherImage drawInRect:imageView.bounds];
      imageView.image = UIGraphicsGetImageFromCurrentImageContext();
      UIGraphicsEndImageContext();
      [self.view addSubview:imageView];
      
  76. 而是怎封装一个view的

    1). 可以通过纯代码或者xib的方式来封装子控件
    2). 建立一个跟view相关的模型,然后将模型数据传给view,通过模型上的数据给view的子控件赋值
    
    /**
     *  纯代码初始化控件时一定会走这个方法
     */
    - (instancetype)initWithFrame:(CGRect)frame {
        if(self = [super initWithFrame:frame]) {
            [self setupUI];
        }
        return self;
    }
    
    /**
     *  通过xib初始化控件时一定会走这个方法
     */
    - (id)initWithCoder:(NSCoder *)aDecoder {
        if(self = [super initWithCoder:aDecoder]) {
            [self setupUI];
        }
        return self;
    }
    
    - (void)setupUI {
        // 初始化代码
    }
    
  77. HTTP协议被 POST 方法与 GET
    方法有那些区别?

    1. GET用于向服务器请求数据,POST用于提交数据
    2. GET请求,请求参数拼接形式暴露在地址栏,而POST请求参数则放在请求体里面,因此GET请求不适合用于验证密码等操作
    3. GET请求的URL有长度限制,POST请求不会有长度限制
    
  78. 求简单的牵线下APNS发送系统信息之机制

    APNS优势:杜绝了类似安卓那种为了接受通知不停在后台唤醒程序保持长连接的行为,由iOS系统和APNS进行长连接替代。
    APNS的原理:
        1). 应用在通知中心注册,由iOS系统向APNS请求返回设备令牌(device Token)
        2). 应用程序接收到设备令牌并发送给自己的后台服务器
        3). 服务器把要推送的内容和设备发送给APNS
        4). APNS根据设备令牌找到设备,再由iOS根据APPID把推送内容展示
    

具体详细说明

看来:

  • JOIN:                                                            
           有相当的便返回。
    • LEFT JOIN:                                                    
           右表中莫,没干,我左表的尽归。
    • RIGHT JOIN:                                                  
           左表中绝非就空着,右表的总体返。
    • FULL JOIN:                                                    
           俩表中起一个即赶回。

常用的吧,inner join,left join,其中inner join 经常省略了。