本分享是面向有意向从事iOS开发的伙伴及苹果产品的发烧友,亦或是已经从事了iOS的开发人员,想进一步提升者。假设您对iOS开发有极高的兴趣,能够与我一起探讨iOS开发。一起学习,共同进步。假设您是零基础。建议您先翻阅我之前分享的iOS开发分分钟搞定C语言系列,然后在開始Objective C语言的学习,假设您遇到问题也能够与我探讨。另外将无偿分享自己整理出来的大概400G iOS学习视频及学习资料,都是干货哦。能够新浪微博私信➕关注极客James,期待与您的共同学习和探讨!
!
由于时间有限,每天在工作之余整理的学习分享,难免有不足之处,也希望各路大神指正!
本次整理的内容涵盖Objective C 语言非常多重要问题及细节。非常重要哦!
made by 极客James
C和OC对照
OC中主要开发在什么平台上的应用程序?
答:能够使用OC开发Mac OS X平台和iOS平台的应用程序OC中新增关键字大部分是以什么开头?
答:OC中新增关键字大部分是以@开头OC中新添加了那些数据类型?
答:Block类型
指针类型(Class, id类型)
空类型
特殊类型(SEL, nil)面向对象特性是什么?
答:继承性,封装性,多态性import和#include有什么差别?
答:import 的功能和 include一样, 是将右边的文件复制到当前import的位置.为了降低程序猿的负担, 防止反复导入, 避免程序猿去书写 头文件卫士, 那么OC给出来一个新的预处理指令import
import长处: 会自己主动防止反复拷贝printf和NSLog有什么差别?
答: NSLog会自己主动换行
NSLog在输出内容时会附加一些系统信息
NSLog和printf接收的參数不一样Foundation有什么作用?
答:Foundation.h我们称之为主头文件, 主头文件里又拷贝了该工具箱中全部工具的头文件, 我们仅仅须要导入主头文件就能够使用该工具箱中全部的工具, 避免了每次使用都要导入一个相应的头文件
面向对象基本概念
什么是面向对象?
答:对象是人们要进行研究的不论什么事物,从最简单的整数到复杂的飞机等均可看作对象,它不仅能表示详细的事物,还能表示抽象的规则、计划或事件。面向对象和面向过程的差别?
答:
1>面向对象是相对面向过程而言
2>面向对象和面向过程都是一种思想
面向过程
强调的是功能行为
关注的是解决这个问题须要哪些步骤
面向对象
将功能封装进对象,强调具备了功能的对象
关注的是解决这个问题须要哪些对象
类与对象
什么是对象?
答:对象是人们要进行研究的不论什么事物。从最简单的整数到复杂的飞机等均可看作对象。它不仅能表示详细的事物,还能表示抽象的规则、计划或事件。什么是类?
答:具有同样特性(数据元素)和行为(功能)的对象的抽象就是类。因此,对象的抽象是类。类的详细化就是对象。也能够说类的实例是对象,类实际上就是一种数据类型。
类由几部分组成?
答: 类(Class) 一个类由3个部分构成
类的名称:类名
类的属性:一组包括数据的属性
类的方法:同意对属性中包括的数据进行操作的方法怎么来定义一个类?
书写类的格式
答:定义类要分为两部分: 声明和实现
类的声明格式
@interface 类名 : 父类名(NSObject)
{
定义实例变量(成员变量,属性)
}
方法的声明
@end
类的实现格式
@implementation 类名
方法的详细实现
@end;
5.OC中属性写在类中哪个位置?
答:OC类声明中属性仅仅能在写@interface和@end之间的{}中
6.怎样通过类创建对象?
书写创建对象格式
答: 创建对象格式:
类名 *指针名 = [类名 new];
7.实例化对象调用哪个方法?实例化对象做了哪3件事?
答:实例化对象调用类方法new
1.给对象分配存储空间
2.初始化类中的实力变量
3.返回对象内存地址
8.怎样訪问对象中的属性?
答:使用指针訪问
格式: 指针名->_属性名;
OC方法
方法和函数的差别?
答:
1)OC中的行为和C语言中的函数一样, 都是用来保存一段特定功能的代码
C语言中定义一个函数, 分为声明和实现, 声明写在.h中, 实现写在.c中
OC中定义一个方法, 也分为声明和实现, 声明写在@interface中, 实现写在@implementationC语言的函数分为两种: 内部函数和外部函数
OC中的方法也分为两种; 类方法和对象方法怎么声明和实现无參无返回值方法的?调用方法的格式?
(书写格式)
答:
方法的声明格式:- (返回值类型)方法名;
方法的实现格式: (返回值类型)方法名{
}
调用方法格式:
[对象名 方法名];
或者 [类名 方法名];小括号在OC方法中有什么用法?
答:OC方法中的()有特殊的用途, OC方法中的()是用来扩住数据类型的有參数方法格式是怎样?
带一个參数
方法声明
·- (返回值类型)方法名:(參数类型)參数名;
方法实现
- (返回值类型)方法名:(參数类型)參数名{
}
带多个參数
方法声明
- (返回值类型)方法名1:(參数类型)參数名1 方法名2:(參数类型)參数名2;
- (返回值类型)方法名1:(參数类型)參数名1 and方法名2:(參数类型)參数名
- (返回值类型)方法名1:(參数类型)參数名1 :(參数类型)參数名2;
方法实现
- (返回值类型)方法名1:(參数类型)參数名1 方法名2:(參数类型)參数名2{
}
OC类方法
类方法和对象方法的差别?
答:
0). 对象方法以-开头
类方法以+开头
1). 对象方法必须用对象调用
类方法必须用类来调用
2).对象方法中能够直接訪问属性(成员变量)
类方法中不能够直接訪问属性(成员变量)
3). 类方法和对象方法能够进行相互调用(展示代码)类方法的应用场景?
答:
类方法一般用于定义工具方法
字符串查找
文件操作
数据库操作isa是什么数据类型?
答: 类的第0个属性并非我们编写的_age, 而是一个叫做isa的属性
isa是对象中的隐藏指针,指向创建这个对象的类,占8个字节
方法和函数的差别
函数和方法的差别?
答:
1).函数属于整个文件, 方法属于某一个类
方法假设离开类就不行
2).函数能够直接调用, 方法必须用对象或者类来调用
注意: 尽管函数属于整个文件, 可是假设把函数写在类的声明中会不识别
3).不能把函数当做方法来调用, 也不能把方法当做函数来调用方法有哪些的注意点?
答:方法能够没有声明仅仅有实现
方法能够仅仅有声明没有实现, 编译不会报错, 可是执行会报错
假设方法仅仅有声明没有实现, 那么执行时会报:
reason: ‘+[Person demo]: unrecognized selector sent to class 0x100001140’
发送了一个不能识别的消息, 在Person类中没有+开头的demo方法
reason: ‘-[Person test]: unrecognized selector sent to instance 0x100400000’常见的错误有哪些?
1.仅仅有类的声明。没有类的实现
2.漏了@end- @interface和@implementation嵌套
4.成员变量没有写在括号中面
5.方法的声明写在了大括号中面
6.成员变量不能在{}中进行初始化、不能被直接拿出去訪问
7.方法不能当做函数一样调用
8.OC方法仅仅能声明在@interface和@end之间,仅仅能实如今@implementation和@end之间。也就是说OC方法不能独立于类存在
9.C函数不属于类,跟类没有联系,C函数仅仅归定义函数的文件全部
10.C函数不能訪问OC对象的成员
11.低级错误:方法有声明。可是实现的时候写成了函数
12.OC能够没有@interface同样能够定义一个类
多文件开发
为什么要使用多文件?
答:
一个iOS项目可能会有多个人开发,假设多个人同一时候改动一个文件,那么就非常可能会产生冲突,比方这个添加一个方法,那个人把这方法删掉了。另外就是当把多个人写功能合并起来的时候,也非常困难,写到一个文件里,无法顺畅的进行团队合作
OC中怎样进行多文件开发?
答:
在工作中,通常把不同的类放到不同的文件里,每一个类的声明和实现分开
声明写在.h头文件里,
实现写在相应的.m文件里去,
类名是什么,文件名称就是什么使用多文件开发有什么长处?
答:
显著提高团队协作的效率
提高程序的开发速度
提高程序的可维护性
提高代码的可读性
面向对象特性
:面向对象三大特性有哪些?
答:继承性,封装性,多态性什么是封装?
封装的长处?封装的规范?
答:
封装: 屏蔽内部实现的细节, 仅仅对外提供共同拥有的方法/接口
长处: 保证数据的安全性,将变化隔离
规范: 普通情况下不会对外直接暴露成员变量, 都会提供一些共同拥有的方法进行赋值
成员变量都须要封装起来为什么要进行封装?
答:一个类把自己的成员变量暴露给外部的时候,那么该类就失去对该成员变量的管理权,别人能够随意的改动你的成员变量。
geeter-setter方法
什么是setter方法?
sett方法的书写格式?
答:setter方法就是给成员变量赋值的方法
格式:
(1) setter方法一定是对象方法
(2) 一定没有返回值
(3) 一定以set开头, 而且set后面跟上须要设置的成员变量的名称去掉下划线, 而且首字母大写
(4) 一定有參数, 參数类型一定和须要设置的成员变量的类型一致, 而且參数名称就是成员变量的名称去掉下划线getter方法就是获取成员变量值的方法
格式:
(1) getter方法一定是对象方法
(2)一定有返回值, 而且返回值一定和获取的成员变量的类型一致
(3)方法名称就是获取的成员变量的名称去掉下划线
(4) 一定没有參数成员变量下面划线开头有什么长处?
答:
1.用于区分局部变量/全局变量/形參
2.方便程序编码, 提高编码效率解释一下什么是仅仅读属性?什么是仅仅写属性?可读可写的属性?
私有属性?
答:
一个属性能够仅仅有getter方法, 没有setter方法, 这样的属性我们称之为仅仅读属性
一个属性也能够仅仅有setter方法, 没有getter方法, 这样的属性我们称之为仅仅写属性
假设既有setter方法又有getter方法, 那么这样的属性我们称之为可读可写的属性
一个属性也能够没有getter和setter, 这样的属性我们称之为私有属性
点语法和self关键字
什么是点语法?点语法的本质?
答:假设给属性提供了getter和setter方法, 那么訪问属性就又多了一种訪问方式 , 点语法.
点语法的本质是调用了一个类的setter和getter方法怎样使用点语法?
答:
点语法是一个编译器的特性, 会在程序翻译成二进制的时候将.语法自己主动转换为setter和getter方法
假设点语法在=号的左边, 那么编译器会自己主动转换为setter方法
假设点语法在=号的右边, 或者没有等号, 那么编译器就会自己主动转换为getter方法点语法注意事项?
答:点语法一般用于给成员变量赋值, 假设不是给成员变量赋值普通情况下不建议使用, 可是也能够使用什么是成员变量?什么是对象方法?
什么是类方法?
答:
成员变量:
成员变量是一个实例对象的详细状态特征,而且这些状态特征是能够改变的。如张三的年龄,身高,体重等
对象方法:
一个实例对象的行为。比方张三具有吃的行为,张三做出这样行为的时候,有可能会影响,自身的某些状态特征。比方张三吃可能会添加张三体重和身高。
类方法:
类方法是某个类的行为,能够直接通过类名调用;假设在类方法中须要使用某些数据,必须通过參数传入。类方法不能訪问成员变量。
怎样使用self?
假设self在对象方法中, 那么self就代表调用当前对象方法的那个对象
假设self在类方法中, 那么self就代表调用当前类方法的那个类
总结:
我们仅仅用关注self在哪一个方法中 , 假设在类方法那么就代表当前类, 假设在对象方法那么就代表”当前调用该方法的对象”self有哪些注意事项?
答:
(1)self会自己主动区分类方法和对象方法, 假设在类方法中使用self调用对象方法, 那么会直接报错
(2)不能在对象方法或者类方法中利用self调用当前self所在的方法self的有哪些使用场景?
答:
能够用于在对象方法之间进行相互调用
能够用于在类方法之间进行相互调用
能够用于区分成员变量和局部变量同名的情况
继承基本概念
- 什么是继承?什么是父类?
什么是子类?怎样实现继承?
答:
1)子类获得父类的特性就是继承
2)被继承的这个类我们称之为父类/ 超类
3)继承了某个类的类我们称之为子类
4)在声明子类的时候。在子类名称后面通过:父类名称方式来实现继承
@interface 子类名称 : 父类名称
@end类
当B类继承A类, 那么B类就拥有A类全部的属性和方法(类方法/对象方法)
2.什么叫方法重写?重写后是以什么顺序调用方法的?
答:
(1)假设子类中有和父类中同名的方法, 那么我们称之为方法重写
注意: 继承中的方法调用顺序, 假设自己有就调用自己的, 假设自己没有就调用父类的
“方法的调用顺序, 先自己再父类, 假设父类中没有再爷爷类, 假设爷爷类再没有就找爷爷的爸爸类
假设一直找到NSObject类都没有找到, 那么就会报错
reason: ‘-[Iphone signalWithNumber:]: unrecognized selector sent to instance 0x1003043c0’
注意:在继承中方法能够重写, 可是属性(成员变量)不能重写
3.方法重写的使用场景?
答:使用场景:当从父类继承的某个方法不适合子类,能够在子类中重写父类的这种方法。
4.继承的条件是什么?
答:
不要以为继承能够提高代码的复用性, 以后但凡发现多个类其中有反复代码就抽取一个父类
仅仅要满足一定的条件我们才干使用继承
条件: XXXX 是 XXX / 某某某 is a 某某某
5.继承的长处是什么?
答:
提高代码的复用性
能够让类与类之间产生关系, 正是由于继承让类与类之间产生了关系所以才有了多态
6.继承的缺点是什么?
答:
耦合性太强(依赖性太强)
super关键字
什么是super?
super是个编译器的指令符号,仅仅是告诉编译器在执行的时候,去调谁的方法.怎么使用super?
答:
super在类方法中, 一定会调用父类的类方法
super在对象方法中, 一定会调用父类的对象方法
能够利用super在随意方法中调用父类中的方法super使用场景?
答:
子类重写父类的方法时想保留父类的一些行为
多态
什么是多态?程序中是怎么体现多态的?
答:
多态就是某一类事物的多种形态
在程序中怎样表现:
父类指针指向子类对象多态的条件是什么?
答:
1)有继承关系
2)子类重写父类方法
3)父类指针指向子类对象多态的长处是什么?
答:提高了代码的扩展性,复用性多态的注意点?
答:假设父类指针指向子类对象, 须要调用子类特有的方法, 必须先强制类型转换为子类才干调用
description方法
使用%@了打印一个对象,输出的是什么内容?%@的原理是什么?
答:%@是用来打印对象的, description方法默认返回对象的描写叙述信息(默认实现是返回类名和对象的内存地址).
事实上%@的本质是用于打印字符串.
仅仅要利用%@打印某个对象, 系统内部默认就会调用父类的description方法
调用该方法, 该方法会返回一个字符串, 字符串的默认格式 <类的名称: 对象的地址>重写description方法注意点?
答:假设在description方法中利用%@输出self会造成死循环
建议: 在description方法中尽量不要使用self来获取成员变量
由于假设你经常在description方法中使用self, 可能已不小心就写成了 %@, self
私有变量和私有方法
- 什么是私有变量?什么是私有方法?
答:
实例变量(成员变量)既能够在@interface中定义, 也能够在@implementation中定义
私有变量:
写在@implementation中的成员变量, 默认就是私有的成员变量, 而且和利用@private修饰的不太一样, 在@implementation中定义的成员变量在其他类中无法查看, 也无法訪问
私有方法:
在@implementation中定义的私有变量仅仅能在本类中訪问
property和synthesize基本使用
@porperty是一个编译器指令
在Xocde4.4之前, 能够使用@porperty来取代getter/setter方法的声明
也就是说我们仅仅须要写上@porperty就不用写getter/setter方法的声明编译器仅仅要看到@property,就知道我们要生成某一个属性的
getter/setter方法的声明@propertyde格式?
答:@property 数据类型 变量名;@synthesize是什么指令?作用是什么?
答:
synthesize是一个编译器指令, 它能够简化我们getter/setter方法的实现@synthesize age = _age; 在给age赋值时,编译器做了哪些事?
@synthesize age = _age;
(1)在@synthesize后面的age,告诉编译器, 须要实现哪个@property生成的声明
(2)告诉@synthesize, 须要将传入的值赋值给谁和返回谁的值给调用者
假设在@synthesize后面没有告诉系统将传入的值赋值给谁, 系统默认会赋值给和@synthesize后面写得名称同样的成员变量
@synthesize age;property增强做了哪些事?
答:
(1)从Xcode4.4以后,对@property进行了增强, 以后仅仅要利用一个@property就能够同一时候生成setter/getter方法的声明和实现
(2)假设没有告诉@property要将传入的參数赋值给谁, 默认@property会将传入的属性赋值给_开头的成员变量
7.@property的使用场景?
答:
假设不想对传入的数据进行过滤, 仅仅是提供方法给外界操作成员变量, 那么就能够使用@property,而且系统会自己主动给我们生成一个_开头的成员变量
8.使用property增强后,什么时候要重写getter/setter方法?
答:使用property增强,仅仅会生成最简单的getter/setter方法的声明和实现, 并不会对传入的数据进行过滤
假设想对传入的数据进行过滤, 那么我们就必须重写getter/setter方法
9.重写getter/setter方法有哪些注意点?
答:
假设重写了setter方法, 那么property就仅仅会生成getter方法
假设重写了getter方法, 那么property就仅仅会生成setter方法
假设同一时候重写了getter/setter方法, 那么property就不会自己主动帮我们生成私有的成员变量
property修饰符
增强@property使用修饰符后的的格式是什么?
答:
格式:
@property(属性修饰符) 数据类型 变量名称;@property 有哪些修饰符?各有什么作用?
答:readwrite: 代表既生成getter方法 , 也生成setter方法
默认情况下 @property就是readwrite的
@property(readwrite) int age;
‘readonly: 代表仅仅生成getter方法不生成setter方法’
能够给setter方法起别名@property(setter=tiZhong:) double weight;
能够给getter方法起别名@property(getter=isMarried) BOOL married;
静态数据类型和动态数据类型
静态数据类型的特点:
在编译时就知道变量的类型,
知道变量中有哪些属性和方法
在编译的时候就能够訪问这些属性和方法,
而且假设是通过静态数据类型定义变量, 假设訪问了不属于静态数据类型的属性和方法, 那么编译器就会报错动态数据类型的特点:
在编译的时候编译器并不知道变量的真实类型, 仅仅有在执行的时候才知道它的真实类型
而且假设通过动态数据类型定义变量, 假设訪问了不属于动态数据类型的属性和方法, 编译器不会报错id和NSObject * 的差别?
答:
NSObject *是一个静态数据类型
id 是一个动态数据类型动态数据类型的应用场景?
答:动态类型主要用在多态, 能够降低代码量, 避免调用子类特有的方法须要强制类型转换动态数据类型的弊端是什么?
答:由于动态数据类型能够调用随意方法, 所以有可能调用到不属于自己的方法, 而编译时又不会报错, 所以可能导致执行时的错误推断数据类型的有哪些方法?(变量 改动为 对象)
答:为了避免动态数据类型引发的执行时的错误, 普通情况下假设使用动态数据类型保存一个对象, 在调用这个变量的方法之前会进行一次推断, 推断当前对象能否够调用这种方法
构造方法
什么是构造方法?
答:
在OC中init开头的方法, 我们称之为构造方法构造方法的用途?
答:
构造方法的用途: 用于初始化一个对象, 让某个对象一创建出来就拥有某些属性和值怎样实现构造方法?
答:
重写init方法, 在init方法中初始化成员变量怎样重写init方法?
答:重写init方法必须依照苹果规定的格式重写, 假设不依照规定会引发一些未知的错误
(1)必须先初始化父类, 再初始化子类
(2)必须推断父类是否初始化成功, 仅仅有父类初始化成功才干继续初始化子类
(3)返回当前对象的地址
- (instancetype)init
{
// 初始化父类
// 仅仅要父类初始化成功 , 就会返回相应的地址, 假设初始化失败, 就会返回nil
// nil == 0 == 假 == 没有初始化成功
self = [super init];
// 推断父类是否初始化成功
if (self != nil) {
// 初始化子类
// 设置属性的值
_age = 6;
}
// 返回地址
return self;
}
自己定义构造方法
什么是自己定义构造方法?
为什么要自己定义构造方法?
(1)自己定义构造方法就是自己定义一个init方法
(2)有时候我们须要在创建某个对象的时候,让对象的某些属性就具有值,这时候就须要传入一些參数给对象的属性,为了满足这个需求,就须要自己定义构造方法自己定义构造方法的格式?
答:
(1)一定是对象方法
(2)一定返回id/instancetype
(3)方法名称一定以init开头
-(instancetype)initWithAge:(int)age;自己定义构造方法在继承中有一个原则?
答:自己的事情自己做,属于谁的属性就由谁来进行操作
父类的属性交给父类的方法来处理,子类的方法处理子类自己独有的属性自己定义构造方法在子类,怎样调用的父类构造方法的?
答:子类在重写自定构造方法时,一般使用super 调用父类的构造方法,先让父类将父类的属性进行初始化
- (instancetype)initWithAge:(int)age andName:(NSString *)name andNo:(int)no
{
if (self = [super initWithAge:age andName:name]) {
_no = no;
}
return self;
}
instancetype和id差别
instancetype和id差别?
答:
(1)id在编译的时候不能推断对象的真实类型
instancetype在编译的时候能够推断对象的真实类型(2)假设init方法的返回值是instancetype, 那么将返回值赋值给一个其他的对象会报一个警告
假设是在曾经, init的返回值是id, 那么将init返回的对象地址赋值给其他对象是不会报错的(3)id能够用来定义变量, 能够作为返回值, 能够作为形參
instancetype仅仅能用于作为返回值instancetype 应用场景?
答:以后但凡自己定义构造方法, 返回值尽量使用instancetype, 不要使用id
类工厂方法
什么是类工厂方法?
答:用于高速创建对象的类方法, 我们称之为类工厂方法类工厂方法应用场景?
答:类工厂方法中主要用于 给对象分配存储空间和初始化这块存储空间类工厂方法使用规范?
答:规范:
1.一定是类方法 +
2.方法名称以类的名称开头, 首字母小写
3.一定有返回值, 返回值是id/instancetype
4.在类工厂方法实现中,调用本类的构造方法,创建实例对象,并返回实例对象
自己定义类工厂方法是苹果的一个规范, 普通情况下, 我们会给一个类提供自己定义构造方法和自己定义类工厂方法用于创建一个对象。
类工厂方法在继承中的注意点
以后但凡自己定义类工厂方法, 在类工厂方法中创建对象一定要使用self来创建,一定不要使用类名来创建。
类的本质及存储细节
- 类的本质是什么?
答:
(1)类事实上也是一个对象, 这个对象会在这个类第一次被使用的时候创建
(2)仅仅要有了类对象, 将来就能够通过类对象来创建实例对象
(3)实例对象中有一个isa指针, 指向创建自己的类对象
(4)类对象中保存了当前对象全部的对象方法
(5)当给一个实例对象发送消息的时候, 会依据实例对象中的isa指针去相应的类对象中查找
(6)全部类对象的继承关系就是元类对象的继承关系
类的启动过程
1.load方法
“load方法调用时间:”
仅仅要程序启动就会将全部类的代码载入到内存中, 放到代码区
“调用次数”
load方法会在当前类被载入到内存的时候调用, 有且仅会调用一次2.initialize方法
“initialize方法调用时间:”
当当前类第一次被使用的时候就会调用(创建类对象的时候)
“调用次数”
SEL类型
SEL是什么类型?
答:
SEL类型代表着方法的签名,在类对象的方法列表中存储着该签名与方法代码的相应关系SEL有什么作用?
答:
(1)SEL类型的第一个作用, 配合对象/类来检查对象/类中有没有实现某一个方法
(2)SEL类型的第二个作用, 配合对象/类来调用某一个SEL方法
(3)配合对象将SEL类型作为方法的形參哪个方法是用来检验对象是否实现了某个方法?
推断实例是否实现某个对象方法
(BOOL)respondsToSelector: (SEL)selector
推断类是否实现某个类方法
(BOOL)instancesRespondToSelector:(SEL)aSelector;哪些方法是用来调用对象中SEL类型相应的方法?
答:
让对象执行某个方法
- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
内存管理
什么是堆?什么是栈?
答:
栈(操作系统):由操作系统自己主动分配释放,存放函数的參数值。局部变量的值等。其操作方式相似于数据结构中的栈(先进后出)。
堆(操作系统):一般由程序猿分配释放。若程序猿不释放。程序结束时可能由系统回收,分配方式相似于链表。什么是内存管理?
答:
所谓内存管理, 就是对内存进行管理, 涉及的操作有
分配内存 : 比方创建一个对象, 会添加内存占用
清除内存 : 比方销毁一个对象, 能减小内存占用内存管理的本质是什么?
答:
OC对象存放于堆里面
非OC对象一般放在栈里面(栈内存会被系统自己主动回收)
MRC内存管理
什么是引用计数器?
答:每一个OC对象都有自己的引用计数器,它是一个整数,表示有多少人正在用这个对象引用计数器的作用?
答:
(1)当使用alloc、new或者copy创建一个对象时,对象的引用计数器默认就是1
(2)当对象的引用计数器为0时,对象占用的内存就会被系统回收
假设对象的计数器不为0,那么在整个程序执行过程,它占用的内存就不可能被回收(除非整个程序已经退出 )怎么操作引用计数器?
答:
给对象发送一条retain消息,能够使引用计数器值+1(retain方法返回对象本身)
给对象发送一条release消息, 能够使引用计数器值-1
给对象发送retainCount消息, 能够获得当前的引用计数器值
须要注意的是: release并不代表销毁\回收对象, 仅仅是计数器-1dealloc 方法的作用?
答:对象即将被销毁时系统会自己主动给对象发送一条dealloc消息 (因此, 从dealloc方法有没有被调用,就能够推断出对象是否被销毁)重写dealloc方法有什么注意点?
答:重写dealloc方法, [super dealloc]一定要写到全部代码的最后内存管理的原则?
答:
(1)谁创建谁release :
假设你通过alloc、new、copy或mutableCopy来创建一个对象。那么你必须调用release或autorelease
(2)谁retain谁release:
仅仅要你调用了retain,就必须调用一次release
(3)总结:
有加就有减,曾经让对象的计数器+1,就必须在最后让对象的计数器-1
setter方法的内存管理
实现set方法内存管理有哪几步?
答:
(1)retain须要使用的对象
(2)release之前的对象
(3)仅仅有传入的对象和之前的不同才须要release和retain
- (void)setRoom:(Room *)room
{
// 仅仅有房间不同才需用release和retain
if (_room != room) {
// 0ffe1 != 0ffe1
// 2.将曾经的房间释放掉 -1
[_room release];
// retain不仅仅会对引用计数器+1, 而且还会返回当前对象
_room = [room retain];
}
}
property修饰符
1.readonly: 仅仅会生成getter方法
readwrite: 既会生成getter也会生成setter, 默认什么都不写就是readwrite
2.getter: 能够给生成的getter方法起一个名称
setter: 能够给生成的setter方法起一个名称
3.retain: 就会自己主动帮我们生成getter/setter方法内存管理的代码
assign: 不会帮我们生成set方法内存管理的代码, 仅仅仅仅会生成普通的getter/setter方法, 默认什么都不写就是assign
4.多线程
atomic :性能低(默认)
nonatomic :性能高
在iOS开发中99.99%都是写nonatomic
property修饰符 有拿几点须要注意的问题?
答:
1.同样类型的property修饰符不能同一时候使用
2.不同类型的property修饰符能够多个结合在一起使用, 多个之间用,号隔开
3.iOS开发中仅仅要写上property, 那么就立马写上nonatomic
什么是循环retain?
答:
假设A对用要拥有B对象, 而B相应又要拥有A对象, 此时会形成循环retain
解决循环retain的方法,一边用retain一边用assign
autorelease 自己主动释放池
什么是自己主动释放池?
答:
autorelease是一种支持引用计数的内存管理方式,仅仅要给对象发送一条autorelease消息,会将对象放到一个自己主动释放池中,当自己主动释放池被销毁时。会对池子里面的全部对象做一次release操作自己主动释放池的长处是什么?
答:
不用再关心对象释放的时间
不用再关心什么时候调用release简述自己主动释放池的原理?
答:
autorelease实际上仅仅是把对release的调用延迟了,对于每一个autorelease,系统仅仅是把该 Object放入了当前的autorelease pool中,当该pool被释放时,该pool中的全部Object会被调用Release。自己主动释放池有哪些注意事项?
答:
(1)在自己主动释放池中创建了对象, 一定要调用autorelease,才会将对象放入自己主动释放池中
(2)一个程序中能够创建N个自己主动释放池, 而且自己主动释放池还能够嵌套
(3)不要再自己主动释放池中使用比較消耗内存的对象, 占用内存比較大的对象
(4)尽量不要再自己主动释放池中使用循环, 特别是循环的次数非常多, 而且还非常占用内存
(5)千万不要写多次autorelease
(6)一个alloc/new相应一个autorelease或者release自己主动释放池是以什么形式存储的?
答: 假设存在多个自己主动释放池的时候, 自己主动释放池是以 “栈” 的形式存储在堆区
栈的特点: 先进后出
ARC内存管理
问题1:ARC的原理是什么?
答:当ARC开启时,编译器将自己主动在代码合适的地方插入retain, release和autorelease,而作为程序猿,全然不须要操心编译器会做错(除非开发人员自己错用ARC了)。ARC有什么长处?
答:
1.全然消除了手动管理内存的烦琐, 让程序猿更加专注于app的业务
2.基本上能够避免内存泄露
3.有时还能更加高速,由于编译器还能够执行某些优化ARC的原则是什么?什么是强指针?什么是弱指针?
答:仅仅要另一个强指针变量指向对象。对象就会保持在内存中
(1)强指针
默认全部指针变量都是强指针
被__strong修饰的指针
(2)弱指针
被__weak修饰的指针ARC下@property修饰符有哪些?
答:
strong : 用于OC对象, 相当于MRC中的retain
weak : 用于OC对象, 相当于MRC中的assign
assign : 用于基本数据类型, 跟MRC中的assign一样ARC中是怎么对对象进行内存管理的?
答:
(1)ARC下单对象内存管理
(2)ARC下,全部的指针都是强指针
(3)ARC, A对象想拥有B对象, 那么就须要用一个强指针指向B对象
(4)A对象不用B对象了, 什么都不须要做, 编译器会自己主动帮我们做ARC怎么解决循环引用问题?
答:
ARC和MRC一样, 假设A拥有B, B也拥有A, 那么必须一方使用弱指针
也就是说 一端用strong ,一端用weak
Category 分类
- 书写Category的格式?
答:
// 分类的声明
@interface ClassName (CategoryName)
NewMethod; //在类别中加入方法
//不同意在类别中加入变量
@end
ClassName: 须要给哪个类扩充方法
CategoryName: 分类的名称
NewMethod: 扩充的方法
// 分类的实现
@implementation ClassName(CategoryName)
NewMethod
… …
@end
ClassName: 须要给哪个类扩充方法
CategoryName: 分类的名称
NewMethod: 扩充的方法
Category的作用?
答:
(1)在不改变原来的类内容的基础上,为类添加一些方法。
(2)一个庞大的类能够分模块开发,由多个人来编写,更有利于团队合作分类,原来类或者父类中的方法调用的顺序?
答:先调用分类中的方法(最后參与编译的分类优先),再调用原来类中的方法,最后掉用父类中的方法
Extension 匿名扩展
什么是类扩展?
答:延展类别又称为扩展(Extension),Extension是Category的一个特例类扩展格式?
答:
类扩展书写格式
@interface 类名 ()
@end类扩展的作用是什么?
答:写在.m文件里,能够为某个类扩充一些私有的成员变量和方法
Block
什么是Block?
答:Block是iOS中一种比較特殊的数据类型,用来保存某一段代码Block的作用?
答:Block用来保存某一段代码, 能够在恰当的时间再取出来调用
功能相似于函数和方法Block的格式?
答:Block的格式:
返回值类型 (^block变量名)(形參列表) = ^(形參列表) {
};
协议
什么是协议?
答:其他语言有接口的概念,接口就是一堆方法的声明没有实现.
OC中没有接口的概念,OC中的接口就是协议.
协议Protocol是由一系列的方法声明组成的书写协议的格式?
答:
格式:
@protocol 协议名称
// 方法声明列表
@end一个类怎么遵循协议?
答:类遵守协议格式:
@interface 类名 : 父类 <协议名称1, 协议名称2,…>
@end
注意:
(1)一个类能够遵守1个或多个协议
(2)不论什么类仅仅要遵守了Protocol,就相当于拥有了Protocol的全部方法声明
4.协议和继承有什么差别?
答:
(1)继承之后默认就有实现, 而protocol仅仅有声明没有实现
(2)同样类型的类能够使用继承, 可是不同类型的类仅仅能使用protocol
(3)protocol能够用于存储方法的声明, 能够将多个类中共同的方法抽取出来, 以后让这些类遵守协议就可以
- 什么是基协议?
答:基协议:是基协议,是最根本最主要的协议。其中声明了非常多最主要的方法。
注意:建议每一个新的协议都要遵守NSObject协议
6.协议有哪些注意事项?
答:
(1)协议仅仅能声明方法, 不能声明属性
(2)父类遵守了某个协议, 那么子类也会自己主动遵守这个协议
(3)在OC中一个类能够遵守1个或多个协议
注意: OC中的类仅仅能有一个父类, 也就是说OC仅仅有单继承
(4)OC中的协议又能够遵守其他协议, 仅仅要一个协议遵守了其他协议, 那么这个协议中就会自己主动包括其他协议的声明
7.协议中控制方法的能否实现的关键字是什么?各有什么作用?
(1)注意: 假设没有使用不论什么关键字修饰协议中的方法, 那么该方法默认就是required的
(2)注意:@required和@optional仅仅使用程序猿之间交流, 并不能严格的控制某一个遵守该协议的类必须要实现该方法, 由于即便不是实现也不会报错, 仅仅会报一个警告
(3)
@required
假设协议中的方法是@required的, 要求遵守协议的类实现@required所修饰的方法,假设没有实现该方法, 那么会报一个警告
(4)
@optional
假设协议中的方法是@optional的, 遵守协议的类可选择实现@optional所修饰的方法,假设没有实现该方法, 那么不会报警告
类型限定
什么是类型限定?
答:类型限定就是限定一个类必须遵守某个协议类型限定的格式?
答:数据类型<协议名称> 变量名
@property (nonatomic, strong) Wife *wife;类型限定有什么注意点?
答:
(1)类型限定是写在数据类型的右边的
(2)尽管在接受某一个对象的时候, 对这个对象进行了类型限定(限定它必须实现某个协议),
可是并不意味着这个对象就真正的实现了该方法. 所以每次在调用对象的协议方法时应该进行一次验证
if ([self.wife respondsToSelector:@selector(cooking)]) {
[self.wife cooking];
}
代理设计模式
代理模式的应用场景?
(1)当A对象想监听B对象的一些变化时, 能够使用代理设计模式
(2)当B对象发生一些事情, 想通知A对象的时候, 能够使用代理设计模式
(3)当对象A无法处理某些行为的时候,想让对象B帮忙处理(让对象B成为对象A的代理对象)用什么类型来接收遵守协议的代理对象?
答:使用id类型接收代理对象简述一下协议的编写规范?
答:
(1)普通情况下, 当前协议属于谁, 我们就将协议定义到谁的头文件里
(2)协议的名称一般以它属于的那个类的类名开头, 后面跟上protocol或者delegate
(3)协议中的方法名称一般以协议的名称protocol之前的作为开头
(4)普通情况下协议中的方法会将触发该协议的对象传递出去
5.普通情况下一个类中的代理属于的名称叫做 delegate
6.当某一个类要成为另外一个类的代理的时候,
普通情况下在.h中用@protocol 协议名称;告诉当前类 这是一个协议.
在.m中用#import真正的导入一个协议的声明
Foundation
什么是框架?
答:
众多功能\API的集合.
框架是由很多类、方法、函数、文档依照一定的逻辑组织起来的集合,以便使研发程序变得更easy,在OS X下的Mac操作系统中大约有80个框架为全部程序开发奠定基础的框架称为Foundation 框架Foundation 框架有什么作用?
答:
1.Foundation框架是Mac\iOS中其他框架的基础
2.Foundation框架包括了非常多开发中经常使用的数据类型:结构体,枚举, 类什么是NSString?
答:一个NSString对象就代表一个字符串(文字内容)
一般称NSString为字符串类怎样创建NSString对象?有几种方法创建一个NSString字符串?
答:
(1)通过@”“直接创建
假设通过@”“创建字符串, 那么会将字符串放到常量区中
假设是字符串常量, 那么仅仅要内容同样 , 不会反复创建
NSString *str1 = @"james";
(2)通过alloc或者类工厂方法创建
假设是通过alloc或者类工厂方法创建, 那么会将字符串放到堆区中
NSString *str2 = [[NSString alloc] initWithString:@"james"];
NSString *str3 = [NSString stringWithFormat:@"jack"];
- 怎样将字符串写入到文件里?
NSString *str = @"iOS";
NSString *path2 = @"/Users/james/Desktop/abc.txt";
BOOL flag = [str writeToFile:path2 atomically:YES encoding:NSUTF8StringEncoding error:nil];
NSLog(@"flag = %i", flag);
6.什么是URL?
答:
(1)URL的全称是Uniform Resource Locator(统一资源定位符)
(2)URL是互联网上标准资源的地址
(3)互联网上的每一个资源都有一个唯一的URL,它包括的信息指出资源的位置
(4)依据一个URL就能找到唯一的一个资源
7.写URL格式?
答: URL = 协议头://主机地址/路径
8.怎样创建URL
答:
(1)通过alloc 或者类工厂方法创建
NSURL *url = [NSURL URLWithString:@"file:///Users/james/Desktop/str.txt"];
NSURL *url = [[NSURL alloc] initWithString:@"file:///Users/james/Desktop/str.txt"];
(2)通过文件路径创建(默认就是file协议的)
NSURL *url = [NSURL fileURLWithPath:@"/Users/james/Desktop/str.txt"];
9.怎样获取本地路径的信息?获取本地路径信息的方法有什么注意点?
答:获取本地路径信息–fileURLWithPath
方法一:
(1)字符串保存路径
NSString *path = @"file://192.168.13.10/Users/james/Desktop/note/ja.txt";
NSLog(@"url编码前: %@", path);
(2)将路径中中文转换为UTF-8编码格式
path = [path stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog(@"url编码后: %@", path);
方法二:
(1)字符串保存路径,假设訪问本机的文件, 能够省略主机地址
NSString *path = @”file:///Users/james/Desktop/note/ja.txt”;
NSLog(@”url编码前: %@”, path);
(2)将路径中中文转换为UTF-8编码格式
path = [path stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog(@”url编码后: %@”, path);
NSURL *url = [NSURL URLWithString:path];
10.获取本地路径的信息
NSURL *url = [NSURL fileURLWithPath:@"/Users/james/Desktop/note/ja.txt"];
NSError *error = nil;
NSString *str = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error];
if (error == nil) {
NSLog(@"str = %@", str);
}else{
NSLog(@"error = %@", [error localizedDescription]);
}
注意点:
URLWithString: 方法不支持中文,所以无法成功创建URL,必须先对路径字符串进行编码
fileURLWithPath: 方法支持中文,而且省略协议头,可是仅仅能获取本地方法
11.怎样获取网络路径的信息?
答:
获取网络路径的信息–URLWithString
NSURL *url = [NSURL URLWithString:@"http://www.baidu.com"];
NSString *str = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
NSLog(@"str = %@", str);
12.怎样将信息写入到指定文件?
答:
方法一:
NSString *str = @"james";
NSString *path = @"file:///Users/james/Desktop/未命名目录/abc.txt";
path = [path stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSURL URLWithString:path];
[str writeToURL:url atomically:YES encoding:NSUTF8StringEncoding error:nil];
方法二:
NSString *str = @"james";
NSString *path = @"/Users/james/Desktop/未命名目录/abc.txt";
NSURL *url = [NSURL fileURLWithPath:path];
[str writeToURL:url atomically:YES encoding:NSUTF8StringEncoding error:nil];
总结:
1.假设多次往同一个文件里写入内容,那么后一次的会覆盖前一次的 \
2.方法名中没有file,路径中要加入上file协议头,假设方法名中有file,路径中就不须要file协议头
NSString
怎样比較两个字符串的”内容”是否同样?
答:
BOOL flag = [str1 isEqualToString:str2];
NSLog(@”flag = %i”, flag);怎样比較两个字符串的”地址”是否同样?
flag = (str1 == str2);
NSLog(@”flag = %i”, flag);怎样比較字符串的大小?
答:用法compare:
NSOrderedAscending 前面的小于后面的
NSOrderedSame, 两个字符串相等
NSOrderedDescending 前面的大于后面的怎样忽略大写和小写进行比較?
[str1 caseInsensitiveCompare:str2];怎样推断字符串是否以什么结尾的?
本质是什么?
答:
本质就是从字符串的最后一个字符開始匹配, 仅仅要不匹配就返回NO
if ([str hasSuffix:@".gif"]) {
NSLog(@"动态图片");
}else{
NSLog(@"不是动态图片");
}
6.怎样获取指定范围内的字符串?
答:
(1)动态获取截取的起始位置
NSUInteger location = [str rangeOfString:@”>”].location + 1;
(2)动态获取截取的长度
NSUInteger length = [str rangeOfString:@"</"].location - location;
NSRange range = NSMakeRange(location, length);
NSString *newStr = [str substringWithRange:range];
NSLog(@"str = %@", str);
NSLog(@"newStr = %@", newStr);
7.怎样替换字符串中的部分字符?
答:
需求: 将&符号替换为/
NSString *str = @"http:&&www.weibo.iosjames.com&img&james.gif";
..OccurrencesOfString: 要替换谁
// withString: 用谁替换
NSString *newStr = [str stringByReplacingOccurrencesOfString:@"&" withString:@"/"];
NSLog(@"newStr = %@", newStr);
8.怎样对字符串首位进行处理?
答:
NSString *str = @"HTTP://www.baidu.com/img/james.GIF";
NSCharacterSet *set = [NSCharacterSet uppercaseLetterCharacterSet];
NSString *newStr = [str stringByTrimmingCharactersInSet:set];
NSLog(@"newStr = |%@|", newStr);
9.怎样给文件路径加入一个目录?
答:
本质就是在字符串的末尾加上一个/ 和指定的内容
注意: 假设路径后面已经有了/, 那么就不会加入了
假设路径后面有多个/, 那么会自己主动删除多余的/, 仅仅保留一个
NSString *newStr = [str stringByAppendingPathComponent:@"james"];
NSLog(@"%@", newStr);
10.怎样获取路径中文件的扩展名?
答:
本质就是从字符串的末尾開始查找., 截取第一个.后面的内容
NSString *newStr = [str pathExtension];
NSLog(@"%@", newStr);
11.怎样删除路径中文件的扩展名?
答:
本质就是从字符串的末尾開始查找.,删除第一个.和.后面的内容
NSString *newStr = [str stringByDeletingPathExtension];
NSLog(@"%@", newStr);
12.怎样给文件路径加入一个扩展名?
答:
本质就是在字符串的末尾加上一个.和指定的内容
NSString *newStr = [str stringByAppendingPathExtension:@"jpg"];
NSLog(@"%@", newStr);
13.怎样将将字符串转换为大写?
答:
NSString *newStr = [str uppercaseString];
NSLog(@"%@", newStr);
14.怎样将字符串转换为小写?
答:
NSString *newStr2 = [newStr lowercaseString];
NSLog(@"%@", newStr2);
15.怎样将字符串的首字符转换为大写
答:
NSString *newStr = [str capitalizedString];
NSLog(@"%@", newStr);
NSMutalbleString
NSMutableString和NSString的差别?
答:
(1)NSString是不可变的, 里面的文字内容是不能进行改动的
(2)NSMutableString是可变的, 里面的文字内容能够随时更改
(3)NSMutableString能使用NSString的全部方法什么是可变字符串?什么是不可变字符串?
答:
不可变字符串:指的是字符串在内存中占用的存储空间固定,而且存储的内容不能发生变化
可变字符串:指的是字符串在内存中占用的存储空间能够不固定,而且存储的内容能够被改动在字符串后面加入一段字符串?
答:
[strM appendString:@"/image"];
NSLog(@"strM = %@", strM);
4.怎样删除字符串中的字符?
技巧: 在开发中, 我们经常利用rangeOfString和deleteCharactersInRange方法配合起来删除指定的字符串
NSRange range = [strM rangeOfString:@"xx"];
[strM deleteCharactersInRange:range];
NSLog(@"strM = %@", strM);
5.怎样在某个字符前面插入love这个单词?
答:
insertString : 须要插入的字符串
atIndex: 从哪里開始插入
NSRange range = [strM rangeOfString:@"xx"];
[strM insertString:@"love" atIndex:range.location];
NSLog(@"strM = %@", strM);
NSArray
什么是NSArray?
答:NSArray是OC中的数组类,开发中建议尽量使用NSArray替代C语言中的数组NSArray有哪些使用注意?
答:
(1)仅仅能存放随意OC对象, 而且是有顺序的
(2)不能存储非OC对象, 比方int\float\double\char\enum\struct等
(3)它是不可变的,一旦初始化完成后,它里面的内容就永远是固定的, 不能删除里面的元素, 也不能再往里面加入元素
(4)NSArray使用NSLog()打印,输出的是小括号的格式。
(5)NSArray中不能存储nil,由于NSArray觉得nil是数组的结束(nil是数组元素结束的标记)。nil就是0。0也是基本数据类型,不能存放到NSArray中。NSArray有哪些经常用法?
答:
- (NSUInteger)count; 获取集合元素个数
- (id)objectAtIndex:(NSUInteger)index; 获得index位置的元素
- (BOOL)containsObject:(id)anObject; 是否包括某一个元素
- (id)lastObject; 返回最后一个元素
- (id)firstObject; 返回最后一个元素
- (NSUInteger)indexOfObject:(id)anObject; 查找anObject元素在数组中的位置(假设找不到,返回-1)
- (NSUInteger)indexOfObject:(id)anObject inRange:(NSRange)range;
在range范围内查找anObject元素在数组中的位置
4.书写NSArray简写形式?
答:
NSArray *arr = [NSArray arrayWithObjects:@"ldda", @"james", @"jjj", nil];
NSArray *arr = @[@"james", @"jasc", @"jjj"];
获取数组元素的简写
NSLog(@"%@", [arr objectAtIndex:0]);
NSLog(@"%@", arr[0]);
5.怎样使用增强for循环,遍历NSArray数组?
答:
逐个取出arr中的元素, 将取出的元素赋值给obj
注意: obj的类型能够依据数组中元素的类型来写, 不一定要写NSObject
for (NSString *obj in arr) {
NSLog(@”obj = %@”, obj);
}
6.怎样使用OC数组的迭代器来遍历数组?
答:
每取出一个元素就会调用一次block
每次调用block都会将当前取出的元素和元素相应的索引传递给我们
obj就是当前取出的元素, idx就是当前元素相应的索引
stop用于控制什么时候停止遍历
[arr enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if (idx == 1) {
*stop = YES;
}
NSLog(@"obj = %@, idx = %lu", obj, idx);
}];
7.怎样对数据进行排序?NSArray *arr = @[@10, @20, @5, @7, @15];
NSLog(@”排序前: %@”, arr);意:**
想使用compare方法对数组中的元素进行排序, 那么数组中的元素必须是Foundation框架中的对象, 也就是说不能是自己定义对象
NSArray *newArr = [arr sortedArrayUsingSelector:@selector(compare:)];
NSLog(@"排序后: %@", newArr);
8.怎样将数组写入文件里?
答:
NSArray *arr = @[@"eee", @"aaa", @"jjj"];
BOOL flag = [arr writeToFile:@"/Users/james/Desktop/abc.plist" atomically:YES];
NSLog(@"flag = %i", flag);
9.将数组写入文件里,有什么注意事项?
答:
注意(1):
假设将一个数组写入到文件里之后, 本质是写入了一个XML文件
在iOS开发中普通情况下我们会将XML文件的扩展名保存为plist
注意(2)
writeToFile仅仅能写入数组中保存的元素都是Foundation框架中的类创建的对象, 假设保存的是自己定义对象那么不能写入
10.怎样从文件里读取数据到NSArray中?
答:
从文件里读取一个数组,此方法在字典转模型中,经经常使用到
NSArray *newArray = [NSArray arrayWithContentsOfFile:@"/Users/james/Desktop/abc.plist"];
NSLog(@"%@", newArray);
NSMutableArray
1.什么是可变数组?
和NSArray有什么差别?
答:
(1)NSMutableArray是NSArray的子类
(2)NSArray是不可变的,一旦初始化完成后,它里面的内容就永远是固定的, 不能删除里面的元素, 也不能再往里面加入元素
(3)NSMutableArray是可变的,随时能够往里面加入\更改\删除元素
2.怎样创建一个空的数组?创建可变数组有什么注意点?
NSMutableArray *arrM = [NSMutableArray array];
NSMutableArray *arrM = [[NSMutableArray alloc] init];
注意:
不能通过@[]来创建一个可变数组, 由于@[]创建出来的是一个不可变的数组
3.怎样给可变数组添加内容?
答:
方法一:
[arrM addObject:@"james"];
方法二:
将指定数组中的元素都取出来, 放到arrM中 \
并非将整个数组作为一个元素加入到arrM中
[arrM addObjectsFromArray:@[@"james", @"jjj"]];
注意:
下面是将整个数组作为一个元素加入
[arrM addObject:@[@"ss", @"jjj"]];
NSLog(@"%@", arrM);
4.怎样给可变数组插入内容?
答:
[arrM insertObject:@"xcq" atIndex:1];
NSRange range = NSMakeRange(2, 2);
NSIndexSet *set = [NSIndexSet indexSetWithIndexesInRange:range];
插入一组数据, 指定数组须要插入的位置, 和插入多少个
[arrM insertObjects:@[@”A”, @”B”] atIndexes:set];
5.怎样删除可变数组中的内容?
答:
删除
[arrM removeObjectAtIndex:0]
删除数组中最后一个元素
[arrM removeLastObject];
删除index位置的元素
[arrM removeObject:@"A"];
6.怎样替换可变数组中的内容?
答:
[arrM replaceObjectAtIndex:1 withObject:@"M"];
//简写:
arrM[0] = @"ZS";
NSLog(@"%@", arrM);
7.怎样获取可变数组中的内容?
答:
NSLog(@"%@", [arrM objectAtIndex:0]);
NSDictionary
什么是字典?
答:OC中的NSDictionary:依据key找到value,字典中存储的东西都是键值对怎样创建字典?
答:
方法一:
NSDictionary *dict = [NSDictionary dictionaryWithObject:@"james" forKey:@"name"];
NSString *name = [dict objectForKey:@"name"];
NSLog(@"name = %@", name);
方法二:
注意: key和value 是一一相应
NSDictionary *dict = [NSDictionary dictionaryWithObjects:@[@"james", @"22", @"1.75"] forKeys:@[@"name", @"age", @"height"]];
NSLog(@"%@ %@ %@", [dict objectForKey:@"name"], [dict objectForKey:@"age"], [dict objectForKey:@"height"]);
方法三:简写:
NSDictionary *dict = @{key:value};
NSDictionary *dict = @{@"name": @"james"};
NSLog(@"%@", dict[@"name"]);
NSDictionary *dict = @{@"name":@"james", @"age":@"30", @"height":@"1.75"};
NSLog(@"%@ %@ %@", dict[@"name"], dict[@"age"], dict[@"height"]);
3.怎样对字典进行遍历?
答:
NSDictionary *dict = @{@"name":@"james", @"age":@"22", @"height":@"1.75"};
//获取字典中key和value的个数, 在字典中key称之为键, value称之为值
NSLog(@"count = %lu", [dict count]);
方法一:老式for循环写法
for (int i = 0; i < dict.count; ++i) {
// 获取字典中全部的key
NSArray *keys = [dict allKeys];
// 取出当前位置相应的key
// NSLog(@"%@", keys[i]);
NSString *key = keys[i];
NSString *value = dict[key];
NSLog(@"key = %@, value = %@", key, value);
}
方法二:增强for循环写法
怎样通过forin遍历字典, 会将全部的key赋值给前面的obj
for (NSString *key in dict) {
NSLog(@"%@", key);
NSString *value = dict[key];
NSLog(@"key = %@, value = %@", key, value);
}
方法三:OC字典的迭代器来遍历
[dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
NSLog(@"key = %@, value = %@", key, obj);
}];
4.怎样对字典文件进行读写?
答:
(1)将字典数据写入文件里
NSDictionary *dict = @{@"name":@"james", @"age":@"22", @"height":@"1.75"};
[dict writeToFile:@"/Users/james/Desktop/info.plist" atomically:YES];
(2)从文件里读取字典数据
注意: 字典和数组不同, 字典中保存的数据是无序的
NSDictionary *newDict = [NSDictionary dictionaryWithContentsOfFile:@"/Users/james/Desktop/info.plist"];
NSLog(@"%@", newDict);
NSArray *arr = @[@10, @20, @30, @5];
[arr writeToFile:@"/Users/james/Desktop/abc.plist" atomically:YES];
NSMutableDictionary
怎样创建一个空的可变字典?
答:
NSMutableDictionary *dictM = [NSMutableDictionary dictionary];怎样给可变字典加入键值对?
答:
[dictM setObject:@"lnj" forKey:@"name"];
简写:
dictM[@"name"] = @"james";
会将传入字典中全部的键值对取出来加入到dictM中
[dictM setValuesForKeysWithDictionary:@{@"age":@"30", @"height":@"1.75"}];
3.怎样删除可变字典键值对?
答:
[dictM removeObjectForKey:@"name"];
[dictM removeObjectsForKeys:@[@"age", @"height"]];
4.怎样改动可变字典中的键值对?
答:利用setObject方法给同名的key赋值, 那么新值会覆盖旧值
[dictM setObject:@"88" forKey:@"age"];
简写:
dictM[@"age"] = @"88";
5.使用可变字典有什么注意事项?
答:
(1)不能使用@{}来创建一个可变的字典
NSMutableDictionary *dictM = @{@”name”:@”james”};//编译就会报错
[dictM setObject:@”30” forKey:@”age”];
(2)
假设是不可变字典, 那么key不能同样
假设是不可变字典出现了同名的key, 那么后面的key相应的值不会被保存
假设是在可变数组中, 后面的会覆盖前面的
NSDictionary *dict = @{@"name":@"lkl", @"name":@"lll"};
NSLog(@"dict = %@", dict);
NSMutableDictionary *dictM = [NSMutableDictionary dictionaryWithObjects:@[@"lkl", @"lll"] forKeys:@[@"name", @"name"]];
NSLog(@"dict = %@", dictM);
6.NSArray和NSDictionary的差别?
答:
NSArray是有序的,NSDictionary是无序的
NSArray是通过下标訪问元素,NSDictionary是通过key訪问元素
NSNumber
1.NSNumber的应用场景?
答:
NSNumber能够将基本数据类型包装成对象,这样就能够间接将基本数据类型存进NSArray\NSDictionary中
2.怎样将基本数据类型转换为对象类型?
答:
int age = 10;
double number= 5.1;
int value = 6;
NSNumber *ageN = [NSNumber numberWithInt:age];
NSNumber *numberN = [NSNumber numberWithDouble:number];
NSNumber *valueN = [NSNumber numberWithInt:value];
NSArray *arr = @[ageN, numberN, valueN];
NSLog(@"arr = %@", arr);
3.怎样将对象类型转换为基本数据类型?
答:
int temp = [ageN intValue];
double temp = [numberN doubleValue];
4.怎样将基本数据类型转换对象类型简写?有什么注意点?
答:
注意: 假设传入的是变量那么必须在@后面写上(), 假设传入的常量, 那么@后面的()能够省略
NSNumber *temp = @(number);
NSNumber *temp =@10.10;
NSLog(@"%@", temp);
NSValue
1.NSValue的应用场景?
答:
(1)NSNumber是NSValue的子类, 但NSNumber仅仅能包装数字类型
(2)NSValue能够包装随意值
因此, 能够用NSValue将结构体包装后,加入NSArray\NSDictionary中
2.怎样利用NSValue包装经常使用的结构体?
答:
CGPoint point = NSMakePoint(10, 20);
NSValue *value = [NSValue valueWithPoint:point];
NSArray *arr = @[value];
NSLog(@"%@", arr);
3.怎样利用NSValue包装自己定义的结构体?
答:
typedef struct{
int age;
char *name;
double height;
}Person;
Person p = {30, "lld", 1.75};
NSDate
1.NSDate的应用场景?
答:NSDate能够用来表示时间, 能够进行一些常见的日期\时间处理
[NSDate date]返回的就是当前0时区的时间
2.怎样获取当前时区的时间?
答:
(1) date方法创建的时间对象, 对象中就保存了当前的时间
NSDate *now = [NSDate date];
(2)获取当前所处的时区
NSTimeZone *zone = [NSTimeZone systemTimeZone];
(3)获取当前时区和指定时区时间的时间差
NSInteger seconds = [zone secondsFromGMTForDate:now];
// NSLog(@"seconds = %lu", seconds);
(4)计算出当前时区的时间
NSDate *newDate = [now dateByAddingTimeInterval:seconds];
NSLog(@"newDate = %@", newDate);
3.怎样格式化时间?
答:
NSDate 转 NSString
(1)创建时间
NSDate *now = [NSDate date];
(2)创建时间格式化
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
(3)指定格式
formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss";
(4)格式化时间
NSString *str = [formatter stringFromDate:now];
NSLog(@"%@", str);
NSString 转 NSDate
(1)获取时间
NSString *str = @"2015-08-20 07:05:26 +0000";
2.创建时间格式化
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
注意:
假设是从NSString格式化为NSDate, 那么dateFormat的格式, 必须和字符串中的时间格式一致, 否则可能转换失败
(3)指定格式
formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss Z";
4.格式化日期
NSDate *date = [formatter dateFromString:str];
NSLog(@"%@", date);
NSCalendar
1.怎样获取当前时间的年月日时分秒?
答:
(1)获取当前时间
NSDate *now = [NSDate date];
NSLog(@"now = %@", now);
获得NSCalendar 日历对象
NSCalendar *calendar1 = [NSCalendar currentCalendar];
// 利用日历类从当前时间对象中获取 年月日时分秒(单独获取出来)
// components: 參数的含义是, 问你须要获取什么?
// 普通情况下假设一个方法接收一个參数, 这个參数是是一个枚举 , 那么能够通过|符号, 连接多个枚举值
NSCalendarUnit type = NSCalendarUnitYear |
NSCalendarUnitMonth |
NSCalendarUnitDay |
NSCalendarUnitHour |
NSCalendarUnitMinute |
NSCalendarUnitSecond;
NSDateComponents *cmps = [calendar1 components:type fromDate:now];
NSLog(@"year = %ld", cmps.year);
NSLog(@"month = %ld", cmps.month);
NSLog(@"day = %ld", cmps.day);
NSLog(@"hour = %ld", cmps.hour);
NSLog(@"minute = %ld", cmps.minute);
NSLog(@"second = %ld", cmps.second);
2.怎样获取当前时间和指定时间的时间差?
答:
1.过去的一个时间
NSString *str = @"2015-06-29 07:05:26 +0000";
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss Z";
NSDate *date = [formatter dateFromString:str];
2.当前的时间
NSDate *now = [NSDate date];
NSLog(@"date = %@", date);
NSLog(@"now = %@", now);
3.比較两个时间
NSCalendar *calendar = [NSCalendar currentCalendar];
NSCalendarUnit type = NSCalendarUnitYear |
NSCalendarUnitMonth |
NSCalendarUnitDay |
NSCalendarUnitHour |
NSCalendarUnitMinute |
NSCalendarUnitSecond;
NSDateComponents *cmps = [calendar components:type fromDate:date toDate:now options:0];
NSLog(@"%ld年%ld月%ld日%ld小时%ld分钟%ld秒钟", cmps.year, cmps.month, cmps.day, cmps.hour, cmps.minute, cmps.second);
NSFileManager
1.什么是NSFileManager?
怎样获取NSFileManager 对象?
答:
NSFileManager是用来管理文件系统的
它能够用来进行常见的文件\目录操作
NSFileManager *manager = [NSFileManager defaultManager];
2.怎样推断一个文件或者目录是否存在?
答:
BOOL flag = [manager fileExistsAtPath:@"/Users/james/Desktop/video/01-NSArray.text"];
NSLog(@"flag = %i", flag);
3.怎样获取文件或目录的属性?
答:
NSDictionary *info = [manager attributesOfItemAtPath:@"/Users/james/Desktop/video/acn.mp4" error:nil];
NSLog(@"info = %@", info);
4.怎样获取目录中全部的文件?
答:
注意:
NSArray *res = [manager contentsOfDirectoryAtPath:@"/Users/xiaomage/Desktop/video" error:nil];
NSLog(@"res = %@", res);
获取当前目录下全部的文件, 能获取子目录下面的文件
NSArray *res = [manager subpathsAtPath:@"/Users/james/Desktop/video"];
NSArray *res = [manager subpathsOfDirectoryAtPath:@"/Users/james/Desktop/video" error:nil];
NSLog(@"res = %@", res);
5.怎样创建目录?
答:
createDirectoryAtPath: 告诉系统目录须要创建到什么位置
withIntermediateDirectories: 假设指定的文件里有一些目录不存在, 是否自己主动创建不存在的目录
attributes: 指定创建出来的目录的属性
error: 是否创建成功, 假设失败会给传入的參数赋值
注意: 该方法仅仅能用于创建目录, 不能用于创建文件
BOOL flag = [manager createDirectoryAtPath:@"/Users/james/Desktop/abc/llq" withIntermediateDirectories:YES attributes:nil error:nil];
NSLog(@"%i", flag);
6.怎样创建文件?
createFileAtPath: 指定文件创建出来的位置
contents : 文件里的内容
attributes: 创建出来的文件的属性
NSData : 二进制数据
注意: 该方法仅仅能用于创建文件, 不能用于创建目录
Copy
1.使用copy功能的前提是什么?
答:
copy : 须要遵守NSCopying协议,实现copyWithZone:方法
使用mutableCopy的前提
须要遵守NSMutableCopying协议,实现mutableCopyWithZone:方法
2.怎样使用copy功能?
答:
一个对象能够调用copy或mutableCopy方法来创建一个副本对象
copy : 创建的是不可变副本(如NSString、NSArray、NSDictionary)
mutableCopy :创建的是可变副本(如NSMutableString、NSMutableArray、NSMutableDictionary)
3.copy基本原则?
答:
改动源对象的属性和行为。不会影响副本对象
改动副本对象的属性和行为,不会影响源对象
4.为什么通过不可变对象调用了copy方法, 不会生成一个新的对象?
答:
由于原来的对象是不能改动的, 拷贝出来的对象也是不能改动的
既然两个都不能改动, 所以永远不能影响到另外一个对象, 那么已经符合需求
所以: OC为了对内存进行优化, 就不会生成一个新的对象
copy内存管理
1.浅复制(浅拷贝。指针拷贝,shallow copy)
源对象和副本对象是同一个对象
源对象(副本对象)引用计数器+1,相当于做一次retain操作
本质是:没有产生新的对象
2.深复制(深拷贝,内容拷贝,deep copy)
源对象和副本对象是不同的两个对象
源对象引用计数器不变,副本对象计数器为1(由于是新产生的)
本质是:产生了新的对象
copy和Property
1.@property中的copy的作用是什么?
答:
(1)防止外界改动内部的数据
(2)能够使用copy保存block, 这样能够保住block中使用的外界对象的命
block默认存储在栈中, 栈中的block訪问到了外界的对象, 不会对对象进行retain
2.@property内存管理原则?
答:
MRC
1> copy : 仅仅用于NSString\block
2> retain : 除NSString\block以外的OC对象
3> assign :基本数据类型、枚举、结构体(非OC对象),当2个对象相互引用,一端用retain,一端用assign
ARC
1> copy : 仅仅用于NSString\block
2> strong : 除NSString\block以外的OC对象
3> weak : 当2个对象相互引用,一端用strong,一端用weak
4> assgin : 基本数据类型、枚举、结构体(非OC对象)
3.怎样解决block中的循环引用?
答:假设对象中的block又用到了对象自己, 那么为了避免内存泄露, 应该将对象修饰为__block
__block Person *p = [[Person alloc] init]; // 1
p.name = @"james";
NSLog(@"retainCount = %lu", [p retainCount]);
p.pBlock = ^{
NSLog(@"name = %@", p.name); // 2
};
NSLog(@"retainCount = %lu", [p retainCount]);
p.pBlock();
自己定义类实现Copy
1.自己定义类怎样实现copy操作?
答:
(1)以后想让自己定义的对象能够被copy仅仅须要遵守NSCopying协议
(2)实现协议中的- (id)copyWithZone:(NSZone *)zone
(3)在- (id)copyWithZone:(NSZone *)zone方法中创建一个副本对象, 然后将当前对象的值赋值给副本对象就可以
- (id)copyWithZone:(NSZone *)zone
{
// 1.创建一个新的对象
Person *p = [[[self class] allocWithZone:zone] init];
// 2.设置当前对象的内容给新的对象
p.age = _age;
p.name = _name;
// 3.返回新的对象
return p;
}
- (id)mutableCopyWithZone:(NSZone *)zone
{
// 1.创建一个新的对象
Person *p = [[[self class] allocWithZone:zone] init];
// 2.设置当前对象的内容给新的对象
p.age = _age;
p.name = _name;
// 3.返回新的对象
return p;
}
单例ARC和MRC写法
1.什么是单例模式?
答:类的对象成为系统中唯一的实例,提供一个訪问点,供客户类 共享资源
单例就是不管怎么创建都仅仅能有一个实例对象
2.什么情况下使用单例?
答:
(1)类仅仅能有一个实例,而且必须从一个为人熟知的訪问点对其进行訪问,比方工厂方法。
(2)这个唯一的实例仅仅能通过子类化进行扩展,而且扩展的对象不会破坏client代码。
3.创建单例对象的方法一般以什么开头?
答:
(1)普通情况下创建一个单利对象都有一个与之相应的类方法
(2)普通情况下用于创建单利对象的方法名称都以share开头, 或者以default开头
单例在多线程的应用?
答:多线程中的单例
+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
// 下面代码在多线程中也能保证仅仅执行一次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[super allocWithZone:zone] init];
});
return _instance;
}