我结合了自己近期面试经历,总结了一份iOS面试题,基本会考到,也是比较重要比较重要比较关键的基础知识,供参考。
时间比较短,有些知识层面写的比较浅,覆盖的知识面也不够广,有时间的话我会补充。
面试的话基本会考基础,关于C、C++、数据结构、计算机网络、操作系统、计算机组成原理、数字逻辑等知识可能都会问到,本篇博文也是只针对iOS新手所写。我在总结的时候也是结合代码掌握的,死记硬背效果不太大。
对于即将跳槽的老司机来说,更多的会是项目方面及更深层次的知识点,本博可略过。
哪里出错了请大神指点,万分感谢。
希望大家面试成功~
侵删,联系@Apach3@Apach3。
@property (nonatomic, strong) NSString *string1;
@property (nonatomic, copy) NSString *string2;
- (void)test {
NSMutableString *string = [NSMutableString stringWithFormat:@"apach3"];
self.string1 = string;
self.string2 = string;
sting = nil;
NSLog(@"sting: %@", string);
NSLog(@"sting1: %@", self.string1);
NSLog(@"sting2: %@", self.string2);
}
打印结果为string和string1都为null,string2为apach3,证毕
4. strong:强引用,使用该特性实例变量在赋值时,会释放旧的值同时设置新值,引用计数+1,当引用计数为0的时候,该对象会被从内存中释放,适用于一般OC对象
5. weak:弱引用,不会使引用计数增加,相比于assign,在所指向的对象被释放后,weak指针会被置为nil,这样能有效的防止野指针,多用于处理循环引用(代理或block)的问题、storyboard或xib创建的控件(控件放在view上已经形成了如下引用关系:UIViewController->UIView->subView->UIButton,相当于xib/sb对这个button是强引用,你声明的属性对它是弱引用)
6. unsafe_unretained:同weak类似,或者说assign等同于ARC下的unsafe_unretained,在对象被释放后,该属性不会被设置为nil,后续调用容易造成野指针
7. __autoreleasing:内存管理是谁申请谁释放,__autoreleasing则可以使对象延迟释放,比如想传一个未初始化的对象引用到一个方法中,在此方法中实例化此对象,那么可以用__autoreleasing,例如:
- (void) generateErrorInVariable:(__autoreleasing NSError **)paramError {
NSArray *objects = [[NSArray alloc] initWithObjects:@"A simple error", nil];
NSArray *keys = [[NSArray alloc] initWithObjects:NSLocalizedDescriptionKey, nil];
NSDictionary *errorDictionary = [[NSDictionary alloc] initWithObjects:objects forKeys:keys];
*paramError = [[NSError alloc] initWithDomain:@"MyApp"code:1 userInfo:errorDictionary];
}
- (void)test {
NSError *error = nil;
[self generateErrorInVariable:&error];
NSLog(@"Error = %@", error);
}
@property (nonatomic, assign) id delegate;
,这里用assign的原因是为了在ARC下兼容iOS4及更低版本来实现弱引用机制,所以尽量使用weakreadwrite:这是默认参数,同时生成set和get方法的声明和实现,可读、写
readonly:只生成set方法的声明与实现,只读
atomic:这是默认参数,原子性,性能低,会被加锁(一个操作执行过程不能被中断,要么执行完要么不执行,不可以在中途被CPU暂停调度,在多线程环境下不会出现变量被修改的问题,保证数据同步),做金融等要求高安全的时候使用
nonatomic:非原子性,性能高,不加锁,操作是直接从内存取数值,无法保证数据同步
setter:给成员变量的set方法重命名,set方法默认命名:
- (void)set成员变量名(成员变量名称首字母大写):(成员变量数据类型)成员变量名;
getter:给成员变量的set方法重命名,get方法默认命名:- (成员变量数据类型)成员变量名;
synthesize:合成访问器方法,property声明了成员变量的访问方法,synthesize定义了由property声明的方法
@synthesize name = _name
)frame:该view在父view坐标系统中的位置和大小
bounds:该view在本身坐标系统中的位置和大小
#import
@interface NSArray (MyCategory)
//不会生成添加属性的getter和setter方法,必须我们手动生成
@property (nonatomic, copy) NSString *blog;
@end
#import "NSArray+MyCategory.h"
#import
@implementation NSArray (MyCategory)
// 定义关联的key
static const char *key = "blog";
/**
blog的getter方法
*/
- (NSString *)blog {
// 根据关联的key,获取关联的值。
return objc_getAssociatedObject(self, key);
}
/**
blog的setter方法
*/
- (void)setBlog:(NSString *)blog {
// 第一个参数:给哪个对象添加关联
// 第二个参数:关联的key,通过这个key获取
// 第三个参数:关联的value
// 第四个参数:关联的策略
objc_setAssociatedObject(self, key, blog, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
NSArray *myArray = [[NSArray alloc]init];
myArray.blog = @"https://apach3q.github.io";
NSLog(@"谁说Category不能添加属性?我用Category为NSArray添加了一个blog属性,blog=%@",myArray.blog);
谁说Category不能添加属性?我用Category为NSArray添加了一个blog属性,blog=https://apach3q.github.io
浅拷贝(shallow copy):在浅拷贝操作时,对于被拷贝对象的每一层都是指针拷贝
深拷贝(one-level-deep copy):在深拷贝操作时,对于被拷贝对象,至少有一层是深拷贝
完全拷贝(real-deep copy):在完全拷贝操作时,对于被拷贝对象的每一层都是对象拷贝
1. A类定义协议:@protocol AClassDelegate
,在里面定义方法:- (void)change:(NSInteger)number;
2. A类中声明属性:@property (nonatomic, weak) id
3. A类中声明方法,方法实现通知B类:
if ([self.delegate respondsToSelector:@selector(change:)]) {
[self.delegate change:@100];
}
4. B类遵守A类的代理
,并使用self.delegate = self;
将这个设置为A类的代理,然后实现代理方法:
- (void)change:(NSInteger)number {
NSLog(@"%ld", number);
}
typedef void (^myBlock)(int);
@property (nonatomic, copy) myBlock block;
self.block(100);
__weak typeof(self) weakSelf = self;
self.classA.block = ^(int a) {
weakSelf.label.text = [NSString stringWithFormat:@"%d", a];
};
__weak typeof(self) weakSelf = self;
来写),block的类型是copyM(model):程序中用于处理应用程序逻辑的部分,通常负责存取数据。
V(view): 用于构建视图的类,通常根据model创建视图
C(controller):控制model和view如何展示在屏幕上
C-M:单向通信,controller需要讲model呈现给用户,需要知道模型的一切,还需要有同model完全通信的能力
C-V: controller通过view来布局用户界面
M-V: model独立与UI,并不需要和view直接通信,view通过controller获取model数据
V-C: view不能对controller知道的太多,因此要通过间接通信
addTimer:forMode:
方法来把Timer按照指定模式加入到RunLoop中,这里使用的模式是:NSRunLoopCommonModes
,这个模式等效于NSDefaultRunLoopMode
和NSEventTrackingRunLoopMode
的结合- (void)setObject:(id)anObject forKey:(id)aKey;
int a = 10;//全局初始化区
char *p;//全局未初始化区
main {
int b;//栈区
char s[];//栈区
char *p1;//栈区
char *p2 = "1234";//p2在栈区,1234在常量区
static int c = 0;//全局区
w1 = (char *)malloc(10);
w2 = (char *)malloc(20);//分配得来的10和20字节的区域在堆区
}
1. KVC可以自动将数值或结构体型的数据打包成NSNumber或NSValue对象,但我们不能直接将数值通过KVC赋值,需要把数据转换为NSNumber和NSValue类型传入,可以通过KVC修改、获取属性的值:
Person *person = [[Person alloc] init];
[person setValue:[NSNumber numberWithInteger:5] forKey:@"age"];
NSLog(@"age=%@",[person valueForKey:@"age"]);
2. KVC中可以使用KeyPath,假设people对象有属性address,address有属性country,这样就可以通过- (nullable id)valueForKeyPath:(NSString *)keyPath;
和- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;
来获取、修改对应的对象:
NSString *country = [people valueForKeyPath:@"address.country"];
[people setValue:@"USA" forKeyPath:@"address.country"];
3. KVC提供验证key对应value是否可用的方法- (BOOL)validateValue:(inoutid*)ioValue forKey:(NSString*)inKey error:(outNSError**)outError;
1. setValue:forKey:
方法赋值的原理
例如对于:[item setValue:@"value" forKey:@"property"]
,具体实现为:
首先去模型中查找有没有setProperty,找到,直接调用赋值[self setProperty:@"value"]
去模型中查找有没有property属性,有则直接访问属性赋值property = value
去模型中查找有没有_property属性,有则直接访问属性赋值_property = value
找不到,就会直接报错setValue:forUndefinedKey:
报找不到的错误
2. 使用KVC要有以下三个条件:
必须保证模型中定义的属性要大于或等于字典中key的数量
模型中的基本数据类型无法进行转换
属性的名字必须和键相同,否则找不到相关属性会报错
1. 添加监听:
self.abook = [[Book alloc]init];
self.abook.price = @"0";//先设一个初始值
[_abook addObserver:self forKeyPath:@"price" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];
2. 按钮方法触发监听:[self.abook setValue:newPrice forKey:@"price"];
3. 实现监听:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqual:@"price"]) {
NSLog(@"old price: %@",[change objectForKey:@"old"]);
NSLog(@"new price: %@",[change objectForKey:@"new"]);
}
}
4. 移除监听:
- (void)dealloc {
[_abook removeObserver:self forKeyPath:@"price"];
}
1. A类发送一个通知:
NSNotificationCenter *notification = [NSNotificationCenter defaultCenter];
[notification postNotificationName:@"Apach3NewNotification" object:self];
2. B类注册成为Observer:
NSNotificationCenter *notification = [NSNotificationCenter defaultCenter];
[notification addObserver:self selector:@selector(doNext:) name:@"Apach3NewNotification" object:nil];
3. B类处理通知:- (void)doNext:(NSNotification *)notification;
4. 程序不使用的时候,在dealloc方法中移除观察者:
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
其中File有三种方式:plist、Archive(归档)
DB包括:SQLite、FMDB、CoreData
setImageWithURL:placeholderImage:options:
SDWebImageManagerdownloadWithURL:delegate:options:userInfo:
imageCache:didFindImage:forKey:userInfo:
到SDWebImageManagerwebImageManager:didFinishWithImage:
imageCache:didFindImage:forKey:userInfo:
imageCache:didNotFindImageForKey:userInfo:
connection:didReceiveData:中的ImageIO
connectionDidFinishLoading:
数据下载完成交给SDWebImageDecoder做图片解码处理notifyDelegateOnMainThreadWithInfo:
宣告解码完成,imageDecoder:didFinishDecodingImage:userInfo
回调给SDWebImageDownloaderimageDownloader:didFinishWithImage:
回调给SDWebImageManager告知图片下载完成。加油!