1.
clipsToBounds:是指视图上的子视图,如果超出父视图的部分就截取掉,
masksToBounds:是指视图的图层上的子图层,如果超出父图层的部分就截取掉
2.
// NSArray --> NSMutableArray
NSMutableArray *myMutableArray = [myArray mutableCopy];
// NSMutableArray --> NSArray
NSArray *myArray = [myMutableArray copy];
3.
1.自定义cell时,
若使用nib,使用 registerNib: 注册,dequeue时会调用 cell 的 -
(void)awakeFromNib
不使用nib,使用 registerClass: 注册, dequeue时会调用 cell 的 - (id)initWithStyle:withReuseableCellIdentifier:
2.需不需要注册?
使用dequeueReuseableCellWithIdentifier:可不注册,但是必须对获取回来的cell进行判断是否为空,若空则手动创建新的cell;
使用dequeueReuseableCellWithIdentifier:forIndexPath:必须注册,但返回的cell可省略空值判断的步骤。
4.
如果该类没有ViewController
[[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:alertController animated:YES completion:nil];
5.字典和实体类的转换
[self setValuesForKeysWithDictionary:dict];
6.delegate block属性的关键字
- 为了防止循环引用,delegate的关键字使用weak
- block作为类的属性时用copy
Block属性的声明,首先需要用copy修饰符,因为只有copy后的Block才会在堆中,栈中的Block的生命周期是和栈绑定的
<栈 :由系统维护的局部变量 是存在栈上的,其生命周期随函数的生命周期>
<堆 :由程序员申请空间地址,由程序员手动释放,生命周期受到程序员控制>
使用retain也可以,因为block的retain行为默认是用copy的行为实现的,block变量默认是声明为栈变量的,为了能够在block的声明域外使用,所以要把block拷贝(copy)到堆,所以说为了block属性声明和实际的操作一致,最好声明为copy。
另一个需要注意的问题是关于线程安全,在声明Block属性时需要确认“在调用Block时另一个线程有没有可能去修改Block?”这个问题,如果确定不会有这种情况发生的话,那么Block属性声明可以用nonatomic。如果不肯定的话(通常情况是这样的),那么你首先需要声明Block属性为atomic,也就是先保证变量的原子性(Objective-C并没有强制规定指针读写的原子性)。
参考
7.隐藏UITableBar
当页面使用 UITabBarController + UINavigationController 框架的时候,当跳转到详情页面的时候,如果 UITabBar 仍然存在的话就会造成逻辑混乱,用户体验也会下降,因此我们就有一个在详情页将 UITabBar 隐藏的需求,参考链接
self.hidesBottomBarWhenPushed = YES;
self.tabBarController.tabBar.hidden = NO;
修改 TabBar 的 subview 的 frame
8. id的使用
id <SDWebImageOperation> operation
9. runtime动态添加属性
10. 自定义NSOperation
11.NSURLSession
12.KVO KVC
kvo的用法非常简单。
1,添加观察者
2,在观察者中实现监听方法,observeValueForKeyPath: ofObject: change: context:(通过查阅文档可以知道,绝大多数对象都有这个方法,因为这个方法属于NSObject)
3,移除观察者修改成员变量不会触发监听器,只有修改属性值才行。
例如
self.changeHeight = self.frame.size.height;//能触发
_changeHeight = self.frame.size.height;//不能触发
参考链接手动KVO
[self willChangeValueForKey:@"changeHeight"];
_changeHeight = self.frame.size.height;
[self didChangeValueForKey:@"changeHeight"];
- 禁用自动KVO
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)theKey {
if ([theKey isEqualToString:@"changeHeight"]) {
return NO;
} else {
return [super automaticallyNotifiesObserversForKey:theKey];
}
}
13.HTTPS 验证
14.网络缓存
15.NSURLCache
16.extern const static
- extern 用法
- a.m 文件中定义
#import "a.h"
NSString * const strExtern = @"strExtern";
a.h文件中声明
extern NSString * const strExtern;
b.m 文件对外部变量进行引用
#import "a.h"
NSLog(@"strExtern : %@", strExtern);
- const 用法
- 声明字符串常量
NSString * const strExtern = @"strExtern";
- 以下声明方式的区别
- 声明字符串常量
NSString * const strExtern = @"strExtern";//指针指向的地址(strExtern)不可变
const NSString *strExtern = @"strExtern";//字符串内容(*strExtern)不可变
- static 用法
如果定义在.m文件中则不能对外使用,只能本文件使用
static NSString * const strExtern = @"strExtern";
16. __nullable和 __nonnull
苹果在Xcode 6.3引入了一个Objective-C的新特性:nullability annotations。这一新特性的核心是两个新的类型注释:__nullable和__nonnull。从字面上我们可以猜到,__nullable表示对象可以是NULL或nil,而__nonnull表示对象不应该为空。当我们不遵循这一规则时,编译器就会给出警告。
17. delegate block 的修饰符
18. block 引起的循环引用
某个类将block作为自己的属性变量,然后该类在block的方法体里面又使用了该类本身,即使在你的block代码中没有显式地出现"self",也会出现循环引用!只要你在block里用到了self所拥有的东西!简单说就是
self.someBlock = ^(Type var){
[self dosomething];
或者self.otherVar = XXX;
或者_otherVar = ...
}
- 解决方法
__weak typeof(self) weakSelf = self;
self.blkA = ^{
__strong typeof(weakSelf) strongSelf = weakSelf;//加一下强引用,避免weakSelf被释放掉
NSLog(@"%@", strongSelf->_xxView); //不会导致循环引用.
};
- 总结
分两种环境去解决:
1)ARC环境下:ARC环境下可以通过使用_weak声明一个代替self的新变量代替原先的self,我们可以命名为weakSelf。通过这种方式告诉block,不要在block内部对self进行强制strong引用:(如果要兼容ios4.3,则用__unsafe_unretained代替__weak,不过目前基本不需考虑这么low的版本)
self.arr = @[@111, @222, @333];
__weak typeof(self) weakSelf=self;
self.block = ^(NSString *name){
NSLog(@"arr:%@", weakSelf.arr);
};
2)MRC环境下:解决方式与上述基本一致,只不过将__weak关键字换成__block即可,这样的意思是告诉block:小子,不要在内部对self进行retain了!
19.id数据类型与静态类型
- 虽然说id数据类型可以存储任何类型的对象,但是不要养成滥用这种通用类型
- 如没有使用到多态尽量使用静态类型
- 静态类型可以更早的发现错误(在编译阶段而不是运行阶段)
- 静态类型能够提高程序的可读性
- 使用动态类型前最好判断其真实类型
- 动态类型判断类型
- - (BOOL)isKindOfClass:classObj 判断实例对象是否是这个类或者这个类的子类的实例
20.分类(category)和类扩展(extension)
- 分类中只能添加“方法”,不能增加成员变量。
- 分类中可以访问原来类中的成员变量,但是只能访问@protect和@public形式的变量。如果想要访问本类中的私有变量,分类和子类一样,只能通过方法来访问。
- 虽说category中无法直接添加属性,但是我们在Category中可以利用运行时添加属性:
- (void)setName:(NSString *)name
{
objc_setAssociatedObject(self,
"name",
name,
OBJC_ASSOCIATION_COPY);
}
- (NSString*)name
{
NSString *nameObject = objc_getAssociatedObject(self, "name");
return nameObject;
}
-
分类的执行优先级
- 在本类和分类有相同的方法时,优先调用分类的方法再调用本类的方法。
- 如果有两个分类,他们都实现了相同的方法,如何判断谁先执行?分类执行顺序可以通过targets,Build Phases,Complie Source进行调节,注意执行顺序是从上到下的。(只有两个相同方法名的分类)
-
分类(category)和类扩展(extension)的关系
- 类扩展(extension)是category的一个特例,有时候也被称为匿名分类。他的作用是为一个类添加一些私有的成员变量和方法。
- 类扩展能写点啥?和分类不同,类扩展即可以声明成员变量又可以声明方法。
21.协议
协议中能够声明方法,以及属性。然后问题就来了,不是不能定义成员变量的吗?
对,的确不能定义成员变量,但是属性是什么?属性包含了三个东西:成员变量、setter方法、getter方法。在类中定义的属性,当然三者都有,然而协议中定义的属性只有获取和设置方法,没有成员变量,这就要求该协议的遵守者必须自己写出setter和getter方法的实现。但是有一种情况是不需要的,那就是遵守者本来就有这个属性,此时系统会为这个属性自动生成设置获取方法,既然已经实现了,那么遵守者就没必要去实现协议中的这个属性了。
尽管可以实现“伪属性”,但是,我们还是应该尽量把属性定义在主接口中,而不应该定义在协议中。
22.断言
- (void)printMyName:(NSString *)myName
{
NSAssert(myName != nil, @"名字不能为空!");
NSLog(@"My name is %@.",myName);
}
当传给函数的参数(myName)为空时,断言将被执行,程序Crash,并打印出断言中的描述信息。本例中,在控制台打印出了如下的日志:
NSAssert[1268:a0b] *** Assertion failure in -[ViewController printMyName:]
NSAssert/NSAssert/ViewController.m:38
2013-11-21 13:56:01.927 NSAssert[1268:a0b] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '名字不能为空!'
开发者没有必要在应用程序的每个版本中都进行断言检查,这是因为大多数项目都是有两个版本:Debug版和Release版。在Debug版中,开发者希望所有的断言都检查到,而在Release版中,往往都是禁用断言检查的。设置Release版本中禁用断言的方法如下:
在Build Settings菜单,找到Preprocessor Macros项,Preprocessor Macros项下面有一个选择,用于程序生成配置:Debug版和Release版。选择 Release项,设置NS_BLOCK_ASSERTIONS,不进行断言检查。
23.dispatch_barrier_sync和dispatch_barrier_async
共同点:
1、等待在它前面插入队列的任务先执行完
2、等待他们自己的任务执行完再执行后面的任务
不同点:
1、dispatch_barrier_sync将自己的任务插入到队列的时候,需要等待自己的任务结束之后才会继续插入被写在它后面的任务,然后执行它们
2、dispatch_barrier_async将自己的任务插入到队列之后,不会等待自己的任务结束,它会继续把后面的任务插入到队列,然后等待自己的任务结束后才执行后面任务。
24.NSObject + (void)load
25.__attribute__
26.__IPHONE_OS_VERSION_MAX_ALLOWED __IPHONE_OS_VERSION_MIN_REQUIRED
这些编译期常量, 对运行时的环境判断完全无效, 它告诉编译器用哪一段代码来进行编译, 那那段代码里, 你仍然可以写运行到目标机器里会崩溃的代码
怎么解决? 组合!
- 我先判断编译环境, 以避免低版本SDK不认识高版本SDK的api, 造成编译错误(片段1)
- 在高版本SDK的条件内, 自行开始判断SDK版本, 或responedToSelector都可以,来判断是否使用高版本的api
- 在低版本条件内, 直接用低版本的api
27. NSRunLoop
28. get 请求重定向
- NSURLConnetion方法
使用NSURLConnetion类的NSURLConnectionDataDelegate中的代理方法
(nullable NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(nullable NSURLResponse *)response
- NSURLSession方法
(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
newRequest:(NSURLRequest *)request
completionHandler:(void (^)(NSURLRequest * __nullable))
29.接口函数过期提醒
使用时xcode会提示‘showWithMaskType’ is deprecated:Use show and setDefaultMaskType: instead.
+ (void)showWithMaskType:(SVProgressHUDMaskType)maskType __attribute__((deprecated("Use show and setDefaultMaskType: instead.")));
30 +load,constructor,main的执行顺序
+ (void)load{
NSLog(@"load");
}
__attribute__((constructor))
void constr(){
NSLog(@"before main");
}
输出结果如下:
2016-07-21 22:13:58.591 Study[14185:5421811] load
2016-07-21 22:13:58.592 Study[14185:5421811] before main
2016-07-21 22:13:58.592 Study[14185:5421811] main
31. NSURLProtocol
@interface CustomURLProtocol : NSURLProtocol
@end
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//注册protocol
[NSURLProtocol registerClass:[CustomURLProtocol class]];
return YES;
}
32. NSURLSessionConfiguration
33.FOUNDATION_EXPORT 与#define
34. Keychain
35. CoreText
36. NSUserDefaults
37. WindowLevel
- windowLevel有以下三种:
- UIWindowLevelNormal;// 0.000000
- UIWindowLevelStatusBar;// 1000.000000
- UIWindowLevelAlert;// 2000.000000
1)当Level层级相同的时候,只有第一个设置为KeyWindow的显示出来,后面同级的再设置KeyWindow也不会显示。
2)statusLevelWindow在alertLevelWindow之后调用makeKeyAndVisible,仍然只是显示在alertLevelWindow的下方。这说明UIWindow在显示的时候是不管KeyWindow是谁,都是Level优先的,即Level最高的始终显示在最前面。
38.@synchronized
39.UIView setFrame方法
40.UIView的生命周期
41.delegate 作为属性需要使用weak
delegate作为属性需要是weak?
防止retain cycle循环引用...
比如tableview....UIViewCotroller通过self.view addsubview.已经指向tableview了......所以tableview.delegate = self 和tableview.datasource又指向了viewcontroller,如果此时delegate是strong,就会发生循环引用无法释放,所以这里应该是weak.....
42.readonly
43.__unsafe_unretained
44.UIScrollView下沉64像素
在ViewController中
self.edgesForExtendedLayout = UIRectEdgeNone;
或
self.automaticallyAdjustsScrollViewInsets = NO;
45.bounds与frame的区别
46.获取字符串宽度
[self.titleLabel.text sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:fontSize]}].width]
47.约束
mas_makeConstraints && mas_remakeConstraints && mas_updateConstraints
48.谓词(NSPredicate)
49.ViewController 和 xib关联
1、新建xxViewController 和 xib(xib 文件名与vc相同) ,并且设置xib 的 file’s owner 为xxViewController,
2、Outlets中的view 跟xib中的view做关联,如果没有这一步会报“loaded the "xxxView" nib but the view outlet was not set.”
第一种方法:
CustomViewController* customViewController = [[CustomViewController alloc] initWithNibName:nil bundle:nil];
你可以看现第一个传数是nil, 对没错,传nil也是可以的。因为如果系统发现是nil的话,会在工程的bundle里找与CustomViewController同名的xib文件,因为模版生成的正好名字相同,所以能够正确加载xib文件。
第二种方法:
CustomViewController* customViewController = [[CustomViewController alloc] init];
在这儿我们只是简单的初始化,也能正解加载相应的xib文件,因为他们名字是相同的。
如果xib的名了与类的名字不同呢?
如果不同那么我们就不能用上面的两种方法,必须显示指明xib的名字,如:
CustomViewController* customViewController = [[CustomViewController alloc] initWithNibName:"firstView" bundle:nil]
在这儿我们显示指明是firstView.xib这个文件。
50.枚举
NS_ENUM定义通用枚举,NS_ENUM定义的枚举不能几个枚举项同时存在,只能选择其中一项,
typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) {
SDWebImageDownloaderFIFOExecutionOrder,
SDWebImageDownloaderLIFOExecutionOrder
};
NS_OPTIONS定义位移枚举
typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) {
SDWebImageDownloaderLowPriority = 1 << 0,
SDWebImageDownloaderProgressiveDownload = 1 << 1,
SDWebImageDownloaderUseNSURLCache = 1 << 2,
SDWebImageDownloaderIgnoreCachedResponse = 1 << 3,
};
位移枚举即是在你需要的地方可以同时存在多个枚举值如这样:
SDWebImageDownloaderOptions opt = SDWebImageDownloaderLowPriority | SDWebImageDownloaderIgnoreCachedResponse;
判断的时候是这样
if (options & SDWebImageDownloaderUseNSURLCache){}
51.多线程中的数据同步
dispatch_semaphore
GCD中信号量是dispatch_semaphore_t类型,支持信号通知和信号等待。每当发送一个信号通知,则信号量+1;每当发送一个等待信号时信号量-1,;如果信号量为0则信号会处于等待状态,直到信号量大于0开始执行。根据这个原理我们可以初始化一个信号量变量,默认信号量设置为1,每当有线程进入“加锁代码”之后就调用信号等待命令(此时信号量为0)开始等待,此时其他线程无法进入,执行完后发送信号通知(此时信号量为1),其他线程开始进入执行,如此一来就达到了线程同步目的。@synchronized
NSLock
52. initialize load
+(void)load 在程序运行后立即执行
+(void)initialize 在类的方法第一次被调时执行
53.__block与__weak区别
54. performSelector调用和直接调用区别
performSelector是运行时系统负责去找方法的,在编译时候不做任何校验;如果直接调用编译是会自动校验。如果方法不存在,那么直接调用 在编译时候就能够发现(借助Xcode可以写完就发现),但是使用performSelector的话一定是在运行时候才能发现(此时程序崩溃);Cocoa支持在运行时向某个类添加方法,即方法编译时不存在,但是运行时候存在,这时候必然需要使用performSelector去调用。所以有时候如果使用了performSelector,为了程序的健壮性,会使用检查方法
直接调用方法时候,一定要在头文件中声明该方法的使用,也要将头文件import进来。而使用performSelector时候, 可以不用import头文件包含方法的对象,直接用performSelector调用即可。
55.@autoreleasepool
当需要在程序中创建大量的临时变量时(大量也可指数量多,不确定,比如从数据库中读取数据时),很容易使内存产生峰值又回到内存低谷,这样对程序的性能会产生很大影响,而使用自动释放池后,峰值明显有所下降。
官方提出的解决方案是,在大量产生局部变量的位置用autoreleasepool代码块进行包装。比如for循环中要执行的语句,这样每次for循环结束后就会及时收回临时变量占用的内存空间。
for (int i = 0; i < 10e6; ++i) {
@autoreleasepool {
NSString *str = [NSString stringWithFormat:@"hi + %d", i];
[collection addObject:str];
}
}
56.加载图片的两种方式
-imageNamed: 是读取到内存后会缓存下来,下次再读取时直接从缓存中获取,因此访问效率要比较高。对于图片资源比较小,使用比较频繁的图片,通常会选择使用此种方式来加载。当然,若不需要考虑性能时,直接使用此种方式也是可以的。
-initWithContentsOfFile: 当图片资源比较大,或者图片资源只使用一次就不再使用了,那么使用此种方式是最佳方式。当应用程序需要加载一张比较大的图片并且是一次性使用的,那么是没有必要去缓存这个图片的,用-imageWithContentsOfFile:是最为经济的方式,这样不会因为UIImage元素较多情况下,CPU会被逐个分散在不必要的缓存上而浪费过多CPU时间。另外,当我们的图片不是PNG图片时,我们通常会选择此种方式来加载。
SDWebImageDecoder引发的思考
57.NSData
58.NSCoding
59.属性修饰符
- nullable
- @property(nonatomic,getter=isOn) BOOL on;
60.导航栏遮挡view问题
if (kCurrentFloatDevice > 7.0) {
self.edgesForExtendedLayout = UIRectEdgeNone;
}