List
0. 深复制与浅复制, NSObject万能指针、id指针、instancetype区别,单例import、include、@class的区别
strong 与 weak 区别 #define 和 typedef的区别,
static 与 extern 区别,@required与@optional 区 别,@private、@protected 、@public、@package区别
- 变量的命名规则以及规范(4规则,2规范)
- 数据类型转换
- printf与scanf,自增自减,逻辑运算符
- if 语句,三元表达式,switch-case, break 与 continue 区别
- 四种进制,sizeof运算符,位运算,int类型的修饰符,有符号和无符号
- 格式控制符,垃圾值,选择,冒泡,字符串的常用函数
- 指针的存储,指针是什么?指针类型,指针类型,指针运算,const关键字,
- oc 与 c 的区别 , oc新增的数据类型,面向过程与面向对象
- nil和NULL区别,面向对象的三大特征(每个特征的定义),setter、getter,self
- super、私有属性和私有方法、里氏替换原则,description,SEL
- 点语法、@property、@synthesize;构造方法
- 内存管理,内存管理的原则,野指针与僵尸对象,内存管理方法,自动释放池
- ARC 与 MRC,分类,延展。
- block,协议,代理,协议与继承的区别
- 属性的修饰符 retain,release,copy,assign,atomic,nonatomic,strong,weak,readonly区别
- 结构体和类的区别
- 内存五大区域的概念
Content
深复制与浅复制的区别
- 概念
- 浅复制
- 被复制对象的所有变量都含有与原来的对象相同的值,而其所有的对其他对象的引用都仍然指向原来的对象
- 深复制
- 被复制对象会将所有非引用类型的字段复制给新对象,同时将引用类型所指向地址中存的对象复制给新的对象
- 区别
- 区别
- 浅复制就是对内存地址的复制,让目标对象指针和源对象指向同一片内存空间
- 深复制是指复制对象的具体内容,而内存地址是自主分配的,复制结束之后,两个对象虽然存的值是相同的,但是内存地址不一样,两个对象也互不影响,互不干涉
- 浅复制和深复制的区别仅在于对引用类型的对待上,一个是复制的地址,一个是复制的地址指向位置的数据
- 区别补充
- 一个对象中的变量有的是值类型的,有的是引用类型的.对于值类型来说,它的值就是单纯的值,而对于引用类型来说,它的值是地址
- 当一个对象其中的引用字段所指向的地址中的变量变化时,所有浅复制对象中的该引用字段都会发生变化
- 作用及注意点
- iOS 中不是所有的对象都支持copy/mutableCopy,遵守NSCopying协议的类可以发送copy消息,遵守NSMutableCopying协议的类才可以发送mutableCopy消息
- 浅复制作用是使得两个对象的成员的值保持一致,在给对象赋值和参数传递的场合使用,有时候一个类中没有指针成员,浅复制就比较合适
- 在给一个对象赋值另一个对象,要实现的功能是在对后一个对象做修改或其他操作对原有对象没有影响,这种情况我们就要做深复制
NSObject 万能指针,id 指针,instancetype 的区别
- 概念:
- NSObject万能指针的概念
- NSObject是OC所有类的父类,依据LSP(里氏替换原则),NSObject指针就可以指向任意的OC对象
- 所以,NSObject指针是1个万能指针
- id指针的概念
- id是1个typedef自定义类型的指针,可以指向任意的OC对象
- 所以,id是1个万能指针
- instancetype关键字的概念
- 如果方法的返回值是instancetype,代表方法的返回值是当前这个类的对象
- 区别:
- NSObject万能指针、id指针的区别
- 概念区别
- id指针可以指向任意OC对象,包括非NSObject对象
- 语法区别
- NSObject万能指针,书写时要加*
- id指针是1个typedef类型的指针,重命名的时候已经有*了,书写是不要加*
- 编译检查区别
- 通过NSObject指针去调用对象方法的时候,编译器会做编译检查
- 通过id类型的指针去调用对象方法的时候,编译器直接通过,不做检查
- 缺点区别
- NSObject缺点:如果要调用指向子类对象的独有的方法,必须强制类型转换
- id缺点:id指针不能使用点语法,会编译错误
- id指针、instancetype的区别
- 概念区别
- instancetype只能作为方法的返回值
- id既可以声明指针变量,作为参数,作为返回值
- 类型区别
- instancetype可以返回和方法所在类相同类型的对象
- id只能返回未知类型的对象
单例【OC】
- 概念
- 一个类的对象,无论在何时创建,无论创建多少次,创建出来的对象都是同一个对象
- 实现方式
- + (instancetype)allocWithZone:(struct _NSZone *)zone
{
static id instance = nil;
if(instance == nil)
{
instance = [super allocWithZone:zone];
}
return instance;
} - 一般为此固定格式
- zone参数没有任何意义 //Apple API Reference ""
- 规范
- 如果为一个类设计了单例模式,Apple规范要求为此类提供一个类方法来快速创建对象
- 格式:defaultxxxxx / sharedxxxxxx
- 作用
- 一些需要全局共享的数据
#import、#include、@class的区别
- 概念:
- #include的概念
- 文件包含指令#include,是一个预处理指令
- 作用:
- 可以将指定的文件内容拷贝到写指令的地方
- 双引号“”,现在当前项目的目录找文件
- 尖括号<>,在编译器的目录中找文件
- #import的概念
- #import是一个预处理指令
- #import作为#include的增强版,可以避免头文件的重复包含
- @class的概念
- 不是预处理指令,它的作用仅仅是有声明这样一个类,可以使用该类型
- 区别:
- 三者的区别
- #include是一个预处理指令,会把文件内容拷贝到写指令的地方,重复调用会重复包含
- #import是一个预处理指令,是#include的增强版,可以避免头文件的重复包含
- @class是一个关键字,而不是预处理指令,作用是声明有这样一个类,但是并不会导入类的头文件
- 扩展
- @class的巧妙用法
- @class不需要拷贝文件,所以性能比#import强
- 可以再头文件中只使用@class声明类,然后在.m中,当具体使用到某个类的时候,再去#import包含头文件,可以提高性能
- 相对路径和绝对路径
- 绝对路径:
- 路径从根目录开始
- 相对路径:相对于当前这个文件夹的路径
- 和当前的文件,删除共同的路径部分,剩余的就是相对路径(相对于main.c的同级路径)
strong 与 weak 的区别
- 概念:
- 强指针和弱指针的概念
- 强指针:
- __strong修饰指针
- 弱指针:
- __weak修饰指针
- 区别:
- 本质上来讲,强指针和弱指针没有任何区别
- 但是在ARC机制下,作为回收对象的基准,如果1个对象没有任何强指针指向他,这个对象就会被立即回收,哪怕这个对象还有弱指针在指向它
#define 和 typedef 的区别
- 概念:
- #define的概念
- #define为宏定义语句,也是预处理指令,在编译之前执行
- 用来定义常量,和宏
- 语法:#define 宏名 宏值
- typedef
- typedef常用来定义一个标识符及关键字的别名,是语言编译过程的一部分,并不实际分配内存空间,可以增强程序和标识符的可读性
- 区别:
- #define、typedef在OC和C中的区别
- 从概念上来看:
- typedef只是为了增加可读性而为标识符另起的新名称
- 而#define在程序中是为了定义常量和宏
- 从执行顺序来看:
- typedef是在编译过程中处理
- 而#define是编译过程前,也就是预处理过程
- 扩展
static 和 extern 的区别【C和OC】
- 概念/区别:
- static 和 extern 的概念
- 总的说来,这两个关键字是用来修饰变量和函数
- static 和 extern修饰局部变量
- static修饰局部变量
- 被static修饰的局部变量叫做静态变量
- 静态变量不再存储在栈区域,而是存储在常量区
- 当函数执行完毕后,这个静态变量不会被回收,再次执行这个函数时,会直接拿这个静态变量使用
- 再次执行时声明静态变量的语句会被略过
- static修饰的静态变量的特点
- 作用域:不变
- 生命周期:延长,直至程序结束
- 声明语句只会执行一次,之后再运行直接略过
- extern不能修饰局部变量
- static和extern修饰全局变量
- 如果定义在模块中的全局变量,使用static修饰,只能在当前模块访问
- 如果定义在模块中的全局变量,使用extern修饰 , 可以跨模块访问
- static和extern修饰函数的效果
- 如果函数被static修饰,那么这个函数只能在当前模块调用
- 如果函数被extern修饰,那么这个函数可以跨模块调用
@required 与 @optional 的区别【OC】
- 概念/区别:
- 无论是@required 与 @optional,遵守协议的类如果不实现的话,编译器都不报错
- @required的概念
- 被@required修饰的方法,如果遵守这个协议的类不去实现的话,编译器就会报警告
- @optional的概念
- 被@optional修饰的方法,如果遵守这个协议的类不去实现的话,编译器不报警告
- 扩展:
- 唯一的作用
- 程序默认是@required
- 在于程序员之间的沟通
- 如果有的方法必须要实现,那么就使用@required
- 如果可以实现也可以不实现,就使用@optional
@pirvate、@protected、@public、@package 的区别【OC】
- 概念/区别:
- 访问修饰符分为以下四类
- @private
- 被@private修饰的属性,叫做私有属性,除了这个类的内部,其他地方都是无权访问的
- 父类的私有成员,子类可以继承,但是依旧无法访问继承来的私有成员
- @protected
- 受保护的,被@protected修饰的属性只能在本类和本类的子类中访问
- @package
- 被@package修饰的属性,只能在当前这个target中访问
- @public
- 公共属性,在任意地方都可以访问这些属性
- 扩展:
- 没有为属性添加访问修饰符,默认为@protected
- 访问修饰符的作用域
- 从访问修饰符开始以下,知道遇到另外一个访问修饰符,或大括号,作用结束
- 使用建议
- 对属性进行封装,不使用 @public,用 @property 或 setter、getter 方法
- 如果父类有属性不希望子类访问,用 @private
- 如果父类有属性想给子类访问,但是别的类别想,用 @protected
- 平时编程用默认的 @protected 就足够了
- 权限大小
- @public > @protected > @private
变量的命名规则以及规范【C和OC】
- 概念:
- C语言变量的命名规则以及规范
- 命名规则
- 变量名只能以任意的字母、下划线、$开头,不能以数字开头
- 不能与C语言的关键字重名
- C语言严格区分大小写
- 变量一定要先声明再使用
- 同一个大括号中,不允许定义多个变量名相同的变量(不允许重复定义)
- 命名规范
- 变量的名字要取的有意义,知名达意
- 驼峰式命名,第1个单词的首字母小写,其他单词的首字母大写
- 扩展:
- OC语言中的命名规范更为重要,比如命名类通常以大写字母开头,知名达意,找到能反映变量或对象使用意图的名称尤为重要。富有意义的名称可以显著增强程序的可读性,并可以在调试和文档编写阶段受益匪浅。
- 例如:
- AddressBook —— 可能是个类名
- currentEntry —— 可能是一个对象
- addNewEntry —— 可能是一个方法名
数据类型转换
- 概念:
- 隐式转换:
- 又名自动类型转换
- 当我们为变量赋值的时候,当赋值符号“=”左右两边的数据类型不一致,这个时候C语言会将右侧赋值的类型,转换成左侧变量的类型,进行自动转换
- 显式转换:
- 又名强制类型转换
- 当我们必须要将某一类型的数据强行转换成另外一种类型,则可以利用强制类型转换运算符(说白了就是俩括号)进行转换,这种强制类型转换称为显式转换
- 举例说明数据类型转换
- 显示转换:
- 例1:int num = 3.94;
- 当我们给一个int类型的变量赋值一个小数,C语言就会直接忽略小数部分,数据失真
- 例2:double d1 = 3.14f;
- 当我们给一个double类型的变量赋值一个float类型的小数,精度过高,浪费空间
- 隐式转换:
- 例3:(int)4.2;
- 这个结果是4,强制类型转换的目的是使表达式的值得数据类型发生改变,从而使不同类型数据之间的运算能够进行下去
- 扩展
- 类型转换的弊端
- 由于类型转换将占用系统时间,过多的转换会降低程序的运行效率,在设计程序时应尽量选择好数据类型,以减少不必要的数据转换。
printf 和 scanf
- 概念:
- printf的概念:
- printf的作用:向控制台输出信息
- scanf的概念:
- 接收用户输入的数据,赋值给指定的变量
- 语法格式:
- scanf(“格式控制符”,变量地址列表);
- scanf函数的执行原理:
- scanf是1个阻塞式函数
- 当CPU执行scanf函数的时候,程序就会暂停执行,并等待用户输入数据
- 待用户输入完毕按下回车后,就会将输入的数据赋值给指定变量
- 然后程序往下执
- int 整型
- %d:读取 int 类型的数据,十进制
- %o:读取 int 类型的数据,八进制
- %x:读取 int 类型的数据,十六进制
- ※注:没有二进制输出格式符
- %hd:读取 short int 类型的数据
- %ld:读取 long int 类型的数据
- %lld:读取 long long int 类型的数据
- %u:读取 unsigned int 类型的数据
- %hu:读取 unsigned short 类型的数据
- %lu:读取 unsigned long 类型的数据
- %llu:读取 unsigned long long 类型的数据
- float,double 浮点数类型
- %f:读取 float 类型的数据
- %lf:读取 double 类型的数据
- char 字符类型
- %c:读取 char 类型的数据
- %p
- %p表示输出的格式转换为指针,即输出变量的地址
- 扩展:
- rewind(stdin)的使用需要
- 取地址符的遗落
自增自减
- 概念:
- 自增自减的概念:
- 对变量操作结果增加1或减少1
- 自增自减表达式作为一个表达式,可以用1个变量将表达式的结果存储起来
- 前自增或后自增
- 前自增表达式
- ++num
- 先将自身的值+1,再将自身的值取出来作为表达式的结果
- 后自增表达式
- num++
- 将自身的值取出来作为后自增表达式的结果,然后再将自身的值+1
- 扩展:
- 常作为循环控制条件使用
逻辑运算符
- 概念:
- 概述三种逻辑运算符
- 逻辑与:&&
- 只有当等式两边的条件都成立,整个逻辑表达式才成立
- 逻辑或:||
- 只要有一边的条件成立,整个逻辑表达式就成立
- 只有两边都不成立,整个逻辑表达式才不成立1
- 左边条件成立,右边就不执行了
- 断路问题:
- 逻辑表达式在执行的时候,是先计算左边条件的结果,再计算右边的、如果左边的条件不成立,右边的条件根本不会去执行
- 先考虑断路问题,再考虑优先级
- 逻辑非:!
- 将真变成假,假变成真
- 运算级别高,先取反,再比较
//很简单
//e.g. !num,只要num不为0,!num即为假(0)
//只要num为0 , !num即为真(1) , !表达式
//道理相同
- 概述逻辑运算符的结合性
- &&和||是双目运算符,具有左结合性,也就是需要有两个变量或表达式参与运算
- !为单目运算符,具有右结合性
- 概述逻辑运算符的优先级
- && 和 || 优先级比关系运算符 (>,<,>=,<=,!=,==) 低
- ! 的优先级要比算数运算符 (+,-,*,/,%) 高,更是高于 && 和 ||
- 扩展:
- 常作为判断语句的判断条件使用
if 语句,三元表达式,switch-case的区别
- 概念:
- 概述 if 语句的概念
- 实现1段代码只有在满足指定条件的时候执行,否则不执行
- 执行步骤:
- 先判断if后面的条件表达式的真假
- 如果为真,条件成立就会执行if块中的代码,执行完毕之后再继续往下执行
- 如果为假,条件不成立,会略过if块中的代码继续往下执行
- 概述三元表达式的概念
- 三元表达式的结果:如果条件表达式成立,那么这个三元表达式的结果就是值1,否则就是值2
- 语法:
- 条件表达式 ?值1 : 值2
- 三元表达式可以部分代替 if - else 语句的判断
- 条件表达式的位置,也可以写上一个普通的表达式
- 值1,值2也可以是表达式的形式
- 概述switch-case的概念
- switch是多分支选择语句,处理多种同类型选择,提高可读性
- case 穿透
- 如果case中没有break,那么switch就不会结束
- 会执行下一个case里面的语句,而不进行判断,这个现象就是case穿透现象
- 阐述三者区别和扩展
- 三者的用法不同
- if:通常用来判断某一个范围,条件成立就会执行if块中的代码
- switch:通常用来判断某一些固定值,当满足某一个case的值,就执行这个case里面的语句
- 三元表达式:三元表达式可以部分代替 if - else 语句的判断
- 扩展:
- 三元表达式用于三数排序比大小
- 三元表达式用于枚举性别
break 与 continue 区别
- 概念:
- 概述 break 的概念
- 跳出循环,然后执行循环体以外的内容,另外break也可用在switch-case结构中,作用为跳出switch结构,break只能用在循环结构和switch结构中
- 概述continue的概念
- 加速循环,也就是会忽略continue以下的语句,直接进行下一次循环条件的判定,continue语句只能用在循环语句中
- 区别:
- 作用区别
- continue只是结束本次循环,并不会终止循环
- break则是结束整个循环过程,而不再进行循环条件的判定
- 用途区别
- break可以用在switch-case结构中用来跳出switch-case结构
- continue语句只能用在循环语句中
- 扩展:
- return
- return语句在C中使用
- 跳出当前函数,回到函数的调用处继续执行,并返回一个与函数返回值类型相同的值,若返回值为void类型,则不需要返回值,直接return即可
- return语句在OC中使用
- 跳出当前方法,回到方法的调用处继续执行,并返回一个与方法返回值类型相同的值,这点,和C是相同的
- 不同之处在于,OC中很少很少用到函数,绝大多数为方法
垃圾值
- 概念:
- 概述垃圾值的概念
- 程序作用域执行完毕之后,定义在里面的变量就会被系统立即回收
- 所占用的字节空间被释放,但占用字节的数据不会清空
- 当新变量被分配到这些字节空间,出现的垃圾值就是原来遗留下的值
选择排序和冒泡排序
- 答题顺序:
- 概述选择排序和冒泡排序
- 概念:
- 概述选择排序和冒泡排序
- 选择排序
- 每一趟从待排序的记录中选出关键字最小的记录,顺序放在已排好序的子文件的最后,直到全部记录排序完毕。
- 冒泡排序
- 比较相邻的元素。如果第一个比第二个大,就交换他们两个
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数
- 针对所有的元素重复以上的步骤,除了最后一个
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较
字符串的常用函数
- 答题顺序:
- C语言中字符串的常用函数
- 概念:
- C语言中字符串的常用函数
- puts( )函数
- 用于输出字符串
- 语法格式:puts(字符数组名)
- 优点:自动换行
- 缺点:只能输出字符串
- gets( )函数
- 从控制台接收用户输入的1个字符串数据
- 语法格式:gets(字符串)
- 优点:当用户输入的字符串包含空格的时候,会连空格一起接收
- 缺点:当字符数组长度不够,字符串过长,使用这个函数就会造成崩溃
- 以下四个函数需要声明string.h头文件
- strlen( )函数
- 获取字符串长度,但是不包括‘ ’
- 语法格式:unsigned long len = stolen(字符串1)
- strcmp( )函数
- 用来比较两个字符串大小
- strcmp(字符串1,字符串2)
- 正数1大于2,负数1小于2,零相等,比较的是相同位的字符的ASCII码值的大小
- strcpy( )函数
- 把存储在1个字符数组中的字符串数据拷贝到另外1个字符数组中存储
- strcpy(字符串1,字符串2)//将 字符串2 拷贝到 字符串1 中
- 可能的问题:
- 字符串1的数组长度不够,无法存储字符串2,运行就会崩溃
- 字符串1数组长度过长,以最近的