三年经验之你忽略的小知识点
1、不自定义Cell,利用UITableView的几个属性 做出系统样式的编辑选中
pic-1.jpeg //1.允许在编辑模式中进行多选操作
self.tableView.allowsSelectionDuringEditing = YES;
//2.改变tableView的当前编辑状态
[self.tableView setEditing:!self.tableView.isEditing animated:YES];
//3.获取在编辑状态下被选中的cell
NSArray<NSIndexPath *> *indexPaths = [self.tableView indexPathsForSelectedRows];
2、UITableView容易混淆模糊的属性(驼峰语法看起也头痛^ ~^ !!)
-
allowsSelectionDuringEditing
: 默认NO,编辑模式下是否可以选中 -
allowsSelection
默认YES,控制在,非编辑模式下row是否可以被选中 -
allowsMultipleSelection
默认NO,控制tableview是否能同时多行选中 -
allowsMultipleSelectionDuringEditing
默认NO,控制编辑模式下是否能同时多行选中
3、iOS图片拉伸技巧 代码及storyboard方式
原理: 配置保护哪部分内容,拉伸哪部分
- 1、传入left和top保护宽度(iOS5之前),系统帮你拉伸1X1
//leftCapWidth代表左端盖宽度,topCapHeight代表顶端盖高度
- (UIImage *)stretchableImageWithLeftCapWidth:(NSInteger)leftCapWidth topCapHeight:(NSInteger)topCapHeight;
- 2、传入上下左右四个方向需要保护的区域,拉伸不需要保护的地方(iOS)
//UIEdgeInsets类型的参数 内边距
- (UIImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets
PS:不知道拉伸区域为负数会如何,晚上实验一下
- 3、iOS6之后的方法。 在上个方法基础上加了伸缩模式:平铺/拉伸
//UIEdgeInsets类型的参数 内边距
//UIImageResizingMode 通过拉伸UIEdgeInsets指定的矩形区域来填充图片
- (UIImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets resizingMode:(UIImageResizingMode)resizingMode
三种代码方式原理详细见解请看这位作者 iOS图片拉伸原理介绍
-
4、storyboard在Asset中设置,一劳永逸。配置好就不用代码了
参数配置参考第三条。
storyboard.png
4、iOS图片缩小方法 (show code)
//img:为传入的图片; size:为放置图片区域的大小; scaledImage:为返回压缩后的图片
+ (UIImage *)scaleToSize:(UIImage *)img size:(CGSize)size{
// 创建一个bitmap的context
// 并把它设置成为当前正在使用的context
UIGraphicsBeginImageContext(size);
// 绘制改变大小的图片
[img drawInRect:CGRectMake(0,0, size.width, size.height)];
// 从当前context中创建一个改变大小后的图片
UIImage* scaledImage =UIGraphicsGetImageFromCurrentImageContext();
// 使当前的context出堆栈
UIGraphicsEndImageContext();
//返回新的改变大小后的图片
return scaledImage;
}
5、KVC将字典赋值到模型中
- KVC :Key Value Coding 即键值编码,通常是用来给某一个对象的属性进行赋值
[obj setValuesForKeysWithDictionary:(NSDictionary<NSString *,id> *)];
6、修饰block为什么要用copy delegate要用weak
Block
- block是一个对象, 所以block理论上是可以retain/release的. 但是block在创建的时候它的内存是默认是分配在栈(stack)上, 而不是堆(heap)上的. 所以它的作用域仅限创建时候的当前上下文(函数, 方法...), 当你在该作用域外调用该block时, 程序就会崩溃.
- 在方法中的block创建在栈区, 使用copy就能把他放到堆区, 这样在作用域外调用该block程序就不会崩溃.
Delegate
delegate 要用weak,主要是考虑到循环引用的问题。
- 如果delegate用强引用。A对象持有B对象,A又作为B对象的代理。两者之间就有两条强引用。A想要释放的时候,B强引用释放不了。B想释放,A又强引用着。造成循环引用。
7、id 与 instancetype 使用区别及举例理解 以及初始化方法为什么不用(ClassName *)返回示例对象
- 首先instancetype、id都是任意对象类型
- instancetype自动识别当前是哪个类在调用,就会变成相应类的对象
- id 首先不能使用
.
语法。 - id可以作为方法的参数,但instancetype不可以
- id 可以调用任何对象的方法,这样就不利于编译器检查错误
@interface Shop :NSObject
+(instancetype)shopWithName:(NSString *)name; ------1 写法
+(id)shopWithName:(NSString *)name; ------2 写法
@end
- (void)viewDidLoad{
[super viewDidLoad];
[[Shop shopWithName] setFrame:CGRectZero];
}
如果shopWithName
是1写法
,编译器就会报错,是2写法
,编译器就不会报错。
- 初始化方法为什么不用(ClassName *)返回示例对象呢
原因:比如说一个Animal类,是用+(Animal *)animalWithName:(NSString *)name
这种方法书写的便利构造。那么当有一个子类Dog继承于他,没有书写任何东西,像下面这样调用:
- (void)viewDidLoad{
[super viewDidLoad];
//子类可以使用父类非privated的属性和方法
Dog *dog = [[Dog animalWithName];
}
+(Animal *)animalWithName:(NSString *)name
返回的是一个Animal对象,你赋值给Dog类实例,系统就会在这儿提出警告说你类型不匹配。
8、KVC系统查找顺序
当调用setValue:属性值 forKey:@”name“的代码时:以@property name
为例;
首先查找对象有没有setName,有则调用set方法赋值
没有找到set方法,就查找对象的成员变量有没有_name,有就_name = value
如果没有找到_name,还会去对象中查找name属性
最终没有找到则报错
9、宏及宏定义常见书写介绍
- 宏里边可变参数:是三个点
...
- 宏定义中的函数的可变参数:
__VA_ARGS__
这句话理解就是:__Value_ Arguments__
value:值 Arguments__:参数
举例:
#ifdef DEBUG
#define NSLog(FORMAT, ...) fprintf(stderr,"%s\n",[[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]);
#else
#define NSLog(...)
#endif
10、模拟器 模拟内存警告
操作步骤:
一、实现测试内存警告接收方法
//appdelegate.m文件实现应用程序接收内存警告协议方法
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application{
NSLog(@"%s",__func__);
}
二、模仿内存警告
操作:
1.Debug-》Simulate Memory Warning
samulator.png
11、自定义控制器View
做法:重写控制器的-loadView
方法。
- (void)loadView{
self.view = [[UIView alloc]initWithFrame:[UIScreen mainScreen].bounds];
self.view.backgroundColor = [UIColor redColor];
}
-
loadView调用时机:第一次使用控制器的View的时候调用。
-
注意:不要调用[super loadView]方法,你调用了super,还不如不重写
-
注意:重写方法中如果没有利用自定义view对
迭代死循环.jpegvc.view
重新赋值,那么就不要去获取控制器的view取使用。会造成死循环,原因参照第一条self.view调用时机。如下图:
12、iOS系统自带方法渲染图片
[[UIImage new] imageWithRenderingMode:UIImageRenderingMode];
13、@synchronized互斥锁简介
- 互斥锁格式:
@synchronized(锁对象){
//需要锁定的代码
}
- 注意:锁定1份代码只能用一把锁,即唯一的锁对象。用多把锁是无效的
- 优点:能有效防止多线程抢夺资源造成的数据安全问题
- 缺点:需要消耗大量的CPU资源
- 使用前提:多条线程抢夺同一块资源,请且对资源有读写操作,且每个线程的顺序是对结果有影响的情况下使用互斥锁。
假如在面试过程中,问到线程同步的东西,这个互斥锁就是使用了线程同步技术。线程同步的意思就是多条线程在同一条线上执行(按顺序执行任务)
14、挺全面的atomic nonatomic 注解
- atomic 的本意是指属性的存取方法是线程安全(thread safe).但不保证整个对象都是线程安全的。比如声明一个atomic修饰的
NSMutableArray
变量marray,此时self.marray
和self.marray = otherarray
都是线程安全的。但是使用[self.marray objectAtIndex:index]
就不是线程安全的,需要配合其他线程安全技术来保证。 - Atomic不能保证对象多线程的安全。所以Atomic 不能保证对象多线程的安全。它只是能保证你访问的时候给你返回一个完好无损的Value而已。举个例子:
如果线程 A 调了 getter,与此同时线程 B 、线程 C 都调了 setter——那最后线程 A get 到的值,有3种可能:可能是 B、C set 之前原始的值,也可能是 B set 的值,也可能是 C set 的值。同时,最终这个属性的值,可能是 B set 的值,也有可能是 C set 的值。所以atomic可并不能保证对象的线程安全。 - nonatomic:对应的就不考虑线程安全
- 说明:atomic要比nonatomic性能慢很多。你想嘛,atomic每次访问Set、get方法之前都加一把锁,性能低很多
15、计算执行一段代码所消耗的时间
- 第一种:
NSDate *begin = [NSDate date];
NSData *data = [NSData dataWithContentsOfURL:url];
NSDate *end = [NSDate date];
NSLog(@"%f",[end timeIntervalSinceDate:begin]);
- 第二种
CFTimeInterval begin = CFAbsoluteTimeGetCurrent();
NSData *data = [NSData dataWithContentsOfURL:url];
CFTimeInterval end = CFAbsoluteTimeGetCurrent();
NSLog(@"%f",end - begin);
16、分离路径字符串的最后一段元素lastPathComponent
- 代码示例
NSString *urlPath = @"https://www.jianshu.com/u/8bacdb9ecf00";
NSString *fileName = [urlPath lastPathComponent];
NSLog(@"%@",fileName); //打印结果:8bacdb9ecf00
解释: (来源于苹果官方文档注释)
- The last path component of the receiver.
- Path components are alphanumeric strings delineated by the path separator (slash “/”) or the beginning or end of the path string. Multiple path separators at the end of the string are stripped.
- Note that this method only works with file paths (not, for example, string representations of URLs).
-
- lastPathComponent
是系统为NSString添加的PathExtensions中的一个方法,目的是获取一段路径字符串的最后一段内容。 - 路径是一串字母数字、放在字符串的开头或者结尾路径分隔符(/)的组合。放在字符串最后的
/
大多数情况被省略掉。
注意:这个方法仅仅对字符串类型的路径和链接,对于NSURL类型的需要先转换成NSString对象类型。 - 举例说明
lastPathComponent
对多种字符串的剪裁效果
Receiver’s String Value | String Returned |
---|---|
/tmp/scratch.tiff | scratch.tiff |
/tmp/scratch | scratch” |
/tmp/ | tmp |
scratch/// | scratch |
/ | / |