简单说一下APP的启动过程,从main文件开始说起
程序启动分为两类:1.有storyboard 2.没有storyboard
有storyboard情况下:
1. main函数
2. UIApplicationMain
创建UIApplication对象
创建UIApplication的delegate对象
3. 根据Info.plist获得Main.storyboard的文件名,加载Main.storyboard
4. 创建UIWindow
5. 创建和设置UIWindow的rootViewController
6. 显示窗口
没有storyboard情况下:
1. main函数
2. UIApplicationMain
创建UIApplication对象
创建UIApplication的delegate对象
3. delegate对象开始处理(监听)系统事件
4. 调用application:didFinishLaunchingWithOptions:方法并在其中创建UIWindow
5. 创建和设置UIWindow的rootViewController
6. 显示窗口
简述一下UIViewController的生命周期?
- loadView 正在加载
- viewDidLoad 加载完成
- viewWillAppear 界面即将出现
- viewWillLayoutSubviews 界面将布局子控件
- viewDidLayoutSubviews 界面已经布局子控件
- viewDidAppear 界面已经出现
- viewWillDisappear 界面即将消失
- viewDidDisappear 界面已经消失
- dealloc 界面被销毁
loadView的作用?
- 用于自定义Controller的View
- 代码示例:
- (void)loadView
{
self.view = [[UIImageView alloc] init];
}
控制器通过Storyboard或者Xib创建时的注意事项?
详细blogLink
- 控制器通过storyboard加载,则根据storyboard的描述创建view
- 控制器view通过xib加载,则根据nibName对应的xib创建view
- 若没有指定nibName,则根据与控制器同名的xib创建view
- 没有同名的xib,则根据与控制器名前缀相同不带controller的xib创建view
- 如果都没有,则创建一个空白的xib
xib如何动态处理view布局
- 不使用自动布局时, xib根据控件在xib上的位置来布局
- 使用自动布局时, xib通过约束条件来布局views
- 使用自动布局时, 若只给控件添加了位置约束, 控件的宽高会根据内容动态调整
frame和bounds的区别 ?
- 相同点
- 两者都可以用来改变View的大小
- 不同点
- frame还能改变View的位置, 但是bounds不能改变View的位置
- 改变View的frame, 其子视图的坐标不变; 改变bounds, 子视图的坐标会变!
- Demo解释:
UIView *v1 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 300)];
v1.backgroundColor = [UIColor redColor];
[self.view addSubview:v1];
UIView *v2 = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 100, 100)];
v2.backgroundColor = [UIColor greenColor];
[v1 addSubview:v2];
以上代码得出的效果图:
添加代码v1.bounds = CGRectMake(0, 0, 200, 200)
后的效果图:
- 解释
- 通过以上两张效果图可以看出, v1看似改变了位置, 但如果留意两者的center点, 两者
- 改变v1的bounds时, v1是在Center点保持不变的前提下改变尺寸的, 因而子视图的位置也会跟着一起改变
- 为了避免对子视图的影响, 一般不建议修改bounds
drawRect 和 layoutSubViews 有什么区别 ?
- drawRect能够获取上下文, 主要用于绘图
- layoutSubviews 用于布局子视图的
iOS有几种动画,各自是什么?
动画详解Link
- 转场动画 (CATransition)
- 帧动画 (CAKeyFrameAnimation)
- 隐式动画 (CABasicAnimation)
如何实现一个图形沿一个固定路径移动 ?
- 步骤
- 创建CALayer对象
- 创建动画
- 创建路径
- 动画捆绑路径
- CALayer捆绑动画
- 释放路径
- 代码示例:
CALayer *redLayer = [CALayer layer];
redLayer.backgroundColor = [UIColor redColor].CGColor;
redLayer.frame = CGRectMake(150, 0, 100, 100);
redLayer.cornerRadius = 50;
[self.view.layer addSublayer:redLayer];
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
animation.duration = 3.f;
animation.repeatCount = MAXFLOAT;
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddEllipseInRect(path, NULL, CGRectMake(0, 0, 300, 600));
animation.path = path;
[redLayer addAnimation:animation forKey:nil];
CGPathRelease(path);
ScrollView的contentSize能在viewDidLoad里设置么,为什么?
- 一般情况下是可以的
- 在使用AutoLayout的时候设置了也没用, 因为:
- 系统会在viewDidLayoutSubviews中根据subviews的约束条件重新计算scrollview的contentSize, 并把之前的值覆盖掉
页面间传值的方式有哪些
(详细博客)
- 正向传值
- 定义属性来传值
- 反向传值
- 通过delegate使用代理方法
- 使用block
- 通过通知中心
- 使用通知中心时, 谁要监听值的变化, 谁就注册通知
- 特别要注意,通知的接受者必须存在
- 正向反向都可以使用
- 使用单例(通过单例的属性传值)
如何自动计算Cell的高度
- iOS8以下需要手动计算高度,然后缓存高度。
- iOS8以上可以用self sizing cells, 完全不需要任何计算
- 核心代码
tableView.estimatedRowHeight = xx
tableView.rowHeight = UITableViewAutomaticDimension
CALayer和UIView的区别
- 从属的库不同
- UIView是UIKit的(只能iOS使用)
- CALayer是QuartzCore的(iOS和mac os通用)。
- 继承关系不同(==>表示继承于)
- CALayer==>NSObject
- UIView==>UIResponder==>NSObject,
- 用户触摸功能不同
- 因为UIView继承于UIResponder, 所以可以处理用户触摸功能
- CALayer不能处理用户处理功能
- 其他
- UIView来自CALayer,是对CALayer的高层实现和封装
- CABasicAnimation,CAAnimation,CAKeyframeAnimation等动画类都要加到CALayer上
UITableview的复用机制的原理
- 通过
dequeueReusableCellWithIdentifier
方法,先从复用队列里面通过Identifier查找是否有Cell可以复用 - 如果有就复用,否则就创建新的Cell。
UIButton与UITableView的层级结构
- UIButton ==> UIControl ==> UIView
- UITableView => UIScrollView ==> UIView
- 拓展
- 展示性的控件一般都直接继承于UIView, 例如UILabel, UIImageView
- 响应性的控件一般先继承于UIControl, 再继承于UIView
同一个Lable的Text如何显示不同字体和颜色
- 使用富文本 (NSAttributedString()
- 代码示例:
NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithString:@"hello"];
// 第一个文字显示蓝色
[str addAttribute:NSForegroundColorAttributeName value:[UIColor blueColor] range:NSMakeRange(0, 1)];
//最后两个文字显示红色
[str addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(2, 2)];
// 在不同位置设置不同字体
[str addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:30] range:NSMakeRange(1, 3)];
self.label.attributedText = str;
说下webview与js的交互
- UIWebView提供有直接调用JS方法,但是没有提供JS调用OC的方法
- 可以用第三方实现JS调用OC,比如JavaScriptBridge,EasyJS,Coradova
如果需要一个有序的NSDictionary应该怎么处理?
- 取出字典所有的key, 对key进行排序
- 按照key值顺序输出所有的Value值
断言的使用
-
NSAssert(url != nil, @"URL不能为空");
- 当url == nil时, 程序会报错, 报的错为"URL不能为空"
深浅拷贝的区别和使用场景
- 区别
- 深拷贝是对象拷贝 -> (会创建新对象)
- 浅拷贝是指针拷贝 -> (拷贝的是对象的地址)
- 代码示例:
[NSString copy]; (浅拷贝)
[NSMutableString copy]; (深拷贝)
[NSString mutableCopy]; (深拷贝)
[NSMutableString mutableCopy]; (深拷贝)
weak的使用情景?
- 在 ARC 中,在有可能出现循环引用的时候,通过使用weak修饰来解决
- 自身已经对它进行一次强引用,没有必要再强引用时也会使用 weak
- 例如自定义 IBOutlet 控件属性
assign和weak的区别?
详细博客第12题
- 使用领域不同
- assign既可以用于MRC,也可以用于ARC
- weak只用于ARC
- 在ARC中修饰的变量类型不同
- aasign用于修饰简单的数据类型, 如Int, BOOL等
- weak用于修饰对象
- 在ARC中修饰后的作用不同
- assign修饰的变量在释放时不会置为nil, 修饰的对象会变为僵尸对象, 再次引用会引起崩溃
- weak修饰的对象在释放时会置为nil, 再次引用不会引起崩溃
说说 __block
和__weak
的区别
-
定义
-
__block
告诉block拦截变量时, 拦截其地址 -
__weak
告诉block, 不要对引用的对象进行强引用(即不要对其进行retain)
-
-
作用
- 在MRC中使用
__block
可以解决循环引用问题, 因为截获的是对象的地址, 不会对其进行retain - 在MRC和ARC中使用
__block
, 由于引用是的地址, 因此可以在block内部修改外部的值 - 在ARC中使用
__weak
可以解决循环引用问题
- 在MRC中使用
instancetype与id的区别
- 在ARC环境下:
- 使用Instancetype时, 在编译的时候就会检查实例的类型
- 使用id的话, 编译时不检查类型, 运行时才检查类型
- 在MRC环境下:
- instancetype和id一样,不做具体类型检查
- id可以创建对象, 可以作为方法的参数类型, 但instancetype不可以
- instancetype只适用于作为方法返回值类型
#import和#include的区别, #import<>和 #import ""的区别, #import和@class的区别?
-
#import
和#include
的区别-
#include
是C/C++中使用的,#import
是OC中使用的 -
#include
不能避免头文件被重复包含的问题,#import
可以解决这个问题
-
-
#import<>
和#import ""
的区别-
#import<>
用于导入系统头文件,#import ""
用于导入自己的头文件
-
-
#import
和@class
的区别-
#import
会包含这个类的所有信息,包括变量和方法,而@class
只是告诉编译器,其后面声明的名称是类的名称,不包括变量和方法 - .h文件中一般使用
@class
来声明类。 而在.m文件中,因为会用到这个类内部的变量和方法,所以需要使用#import
-
@class
的编译效率比#import
高 - 如果有循环依赖关系,如:A–>B, B–>A, 使用#import来相互包含,会出现编译错误,如果使用@class在两个类的头文件中相互声明,则不会有编译错误出现。
-
Objective-C中类别, 类扩展和继承的区别?
- 作用不同
- 类别可以用来添加新的方法, 不能添加新的属性
- 类扩展可以添加新的属性(私有), 不能添加新方法
- 继承可以添加新的属性, 可以重写父类的方法, 还可以添加新的方法
- 对类的影响不同
- 类别可以根据功能的不同, 把不同的方法分开放在几个不同的类别, 以可以减少单个文件的体积。
- 类扩展是类的一部分,在编译时随类的生成而生成。
- 继承相当于为原来的父类创建了一个新的子类
如何进行代码做自动布局
- 使用苹果自带的类NSLayoutConstranit
- 使用可视化格式语言 (VFL)
- 使用第三方框架 (Masonry)
简述assign、retain、copy、weak和strong分别在什么情况下使用?
- strong和weak在ARC中用过来修饰对象属性, 表示强弱引用
- retain, assign在MRC中用来修饰对象属性, 表示是否进行retain(引用计数+1)
- assign在ARC中还可以用来修饰普通类型变量
- copy可以用来拷贝对象
- copy用来修饰NSString变量Str, 通过浅拷贝使其他类可修改Str的值
- copy在MRC中通过修饰Block属性, 可以使block被保存到堆上
delegate用什么属性修饰,ARC下与MRC下有何不同,为什么?
详细博客第8题
- ARC中用weak, 可防止循环引用, 对象销毁后还可以将其置nil
- MRC中用assign, 可防止循环引用
NSString,NSArray,NSMutableArray分别用什么属性修饰,原因是什么?
详细博客
- NSString和NSArray用 copy, 浅拷贝, 允许外部引用时同步修改变量的值
- NSMutableArray 用 strong进行强引用, 若使用copy, 在深拷贝的作用下反而会破坏变量的封装性
谈一下关键字const, static和extern的作用?
详细blogLink
- const用于声明常量, 修饰后的变量都是只读的
int const a = 10;
a = 20
//因为变量a被const修饰,就成为了只读,不能被修改赋值了,
所以上面a = 20这行代码是错误的
- static用于声明静态变量(在内存中只创建一次)
- 注意, static声明的静态变量的作用域只存在于当前作用域 (方法/文件)
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
static int i = 0;
i ++;
NSLog(@"i=%d",i);}
//打印结果 (因为变量i在内存中只存在一份!)
i = 1, i = 2, i = 3 ....
}
- extern用于声明外部全局变量或常量
- 在.h中声明全局常量
//声明一些全局常量
extern NSString * const name;
extern NSInteger const count;
- 在.m中初始化常量, 这样只要导入头文件,就可以全局的使用定义的变量或常量
#import
//实现
NSString * const name = @"王五";
NSInteger const count = 3;
@property本质是什么
详细blog链接
- @property = ivar + getter + setter
- 使用@property, 系统默认为完成以下操作:
- 创建属性的“偏移量” (offset),表示该变量距离存放对象的内存区域的起始地址有多远。
- 创建method_list (方法列表), 保存setter方法和getter方法
- 创建ivar_list (成员变量列表)
- 创建prop_list (属性列表)
OC语言三大特性的定义和特点以及各自的适用场景
封装
- 特点
- 可以模块化代码
- 使用场景
- 需要做性能优化时
- 需要减少代码量时
继承
- 特点
- 子类拥有父类的(非私有)属性+方法
- 使用场景
- 装饰者模式
多态
- 特点
- 父类指向之类, 动态创建对象
- 使用场景
- 工厂模式
在OC里面,给指定类动态添加行为的方法有哪些
- 继承
- 协议
- 类别