1、为什么说Objective-C是一门动态的语言?
静态、动态是相对的,这里动态语言指的是不需要在编译时确定所有的东西,在运行时还可以动态的添加变量、方法和类。
Objective-C 可以通过Runtime 这个运行时机制,在运行时动态的添加变量、方法、类等,所以说Objective-C 是一门动态的语言。
2、MVC和MVVM,MVP框架
1)MVC:模型-视图-控制器(Model-View-Controller,MVC)简单而言Model持有数据,View显示与用户交互的界面,而View Controller调解Model和View之间的交互。
2)MVVM:模型-视图-视图模型(Model-View-ViewModel)
-----View:UI界面
-------ViewModel:它是View的抽象,负责View与Model之间信息转换,将View的Command传送到Model;
------Model:数据访问层。
mvvm中最需要注意的就是通过将View绑定到ViewModel,然后执行一些命令在向它请求个动作。而反过来,ViewModel跟Model通讯,告诉它更新来响应UI。
3)MVP:
----Model:数据访问层
----View:UI显示界面
----Presenter:负责逻辑的处理即Model层与View之间通信。
MVP 是从经典的模式MVC演变而来但是它们之间有着很重要区别:在MVP中View并不直接使用Model,它们之间的通信是通过Presenter (MVC中的Controller)来进行的,所有的交互都发生在Presenter内部,而在MVC中View会从直接Model中读取数据而不是通过 Controller。
3、为什么代理要用weak?代理的delegate和dataSource有什么区别?delegate和block的区别?
1)weak:指明该对象并不负责保持delegate这个对象,delegate这个对象的销毁由外部控制。
2)--- delegate是委托的意思,在oc中则是一个类委托另一个类实现某个方法。当一个对象接受到某个事件或者通知的时候, 会向它的Delegate对象查询它是否能够响应这个事件或者通知,如果可以这个对象就会给它的Delegate对象发送一个消息(执行一个方法调用)。
---- datasource字面是数据源,一般和Delegate伴生,这时数据源处理的数据就是Delegate中发送委托的类中的数据,并通过Datasource发送给接受委托的类。
3)delegate和block的区别:
a、从源头上理解和区别block和delegate:
delegate运行成本低,block的运行成本高。block出栈需要将使用的数据从栈内存拷贝到堆内存,当然对象的话就是加计数,使用完或者block置nil后才消除。delegate只是保存了一个对象指针,直接回调,没有额外消耗。就像C的函数指针,只多做了一个查表动作。
b、从使用场景区别block和delegate:有多个相关方法。假如每个方法都设置一个 block, 这样会更麻烦。而 delegate 让多个方法分成一组,只需要设置一次,就可以多次回调。当多于 3 个方法时就应该优先采用 delegate。当1,2个回调时,则使用block。
delegate更安全些,比如: 避免循环引用。使用 block 时稍微不注意就形成循环引用,导致对象释放不了。这种循环引用,一旦出现就比较难检查出来。而 delegate 的方法是分离开的,并不会引用上下文,因此会更安全些。
它们之前更多区别可以看http://blog.csdn.net/vbirdbest/article/details/51878995
4、属性的实质是什么?包括哪几个部分?属性默认的关键字都有哪些?@dynamic关键字和@synthesize关键字是用来做什么的?
1)属性的实质:实例变量+get方法+set方法,也就是说使用@property 系统会自动生成setter和getter方法;
2)属性默认的关键字包括atomic,nonatomic,@synthesize,@dynamic,getter=getterName,setter=setterName,readwrite,readonly,assign,retain,copy。
3)@dynamic:表示变量对应的属性访问器方法,是动态实现的,你需要在 NSObject 中继承而来的 +(BOOL) resolveInstanceMethod:(SEL) sel 方法中指定 动态实现的方法或者函数。
@synthesize:如果没有实现setter和getter,编译器能够自动实现getter和setter方法。
5、属性的默认关键字是什么?
在objective-c 属性设置里面 默认的就是atomic ,意思就是 setter /getter函数是一个原子操作。
6、NSString为什么要用copy关键字,如果用strong会有什么问题?
1)因为父类指针可以指向子类对象,使用copy的目的是为了让本对象的属性不受外界影响,使用copy无论给我传入是一个可变对象还是不可对象,我本身持有的就是一个不可变的副本。
2)使用是strong,那么这个属性就有可能指向一个可变对象,如果这个可变对象在外部被修改了,那么会影响该属性。
-----------copy此特质所表达的所属关系与strong类似。然而设置方法并不保留新值,而是将其“拷贝” (copy)。 当属性类型为NSString时,经常用此特质来保护其封装性,因为传递给设置方法的新值有可能指向一个NSMutableString类的实例。这个类是NSString的子类,表示一种可修改其值的字符串,此时若是不拷贝字符串,那么设置完属性之后,字符串的值就可能会在对象不知情的情况下遭人更改。所以,这时就要拷贝一份“不可变” (immutable)的字符串,确保对象中的字符串值不会无意间变动。只要实现属性所用的对象是“可变的” (mutable),就应该在设置新属性值时拷贝一份。
7、如何令自己所写的对象具有拷贝功能:若想令自己所写的对象具有拷贝功能,则需实现 NSCopying 协议。如果自定义的对象分为可变版本与不可变版本,那么就要同时实现 NSCopying与 NSMutableCopying协议。
具体步骤:
需声明该类遵从 NSCopying 协议
实现 NSCopying 协议。该协议只有一个方法: - (id)copyWithZone:(NSZone *)zone;
注意:一提到让自己的类用 copy 修饰符,我们总是想覆写copy方法,其实真正需要实现的却是 “copyWithZone” 方法。
8、可变集合类 和 不可变集合类的 copy 和 mutablecopy有什么区别?如果是集合是内容复制的话,集合里面的元素也是内容复制么?
1)使用copy时 可变集合的指针地址以及内存地址都不相同 是深复制 不可变集合的指针地址不一样但是内存地址一样 属于浅复制。使用mutableCopy的时候无论是可变集合还是不可变集合的指针地址和内存地址都不同 都属于深复制。
9、为什么IBOutlet修饰的UIView也适用weak关键字?
因为既然有外链那么视图在xib或者storyboard中肯定存在,视图已经对它有一个强引用了。
10、nonatomic和atomic的区别?atomic是绝对的线程安全么?为什么?如果不是,那应该如何实现?
1)nonatomic和atomic的区别在于两者自动生成getter和setter的方法不一样,如果你自己写getter和setter方法,那么(getter,setter,retain,copy,assign)只起提示作用,写不写都一样。
对于atomic的属性,系统生成的getter和setter会保证get,set的操作完整性,不受其他线程影响。比如线程A的getter方法运行到一半,线程B调用了setter,那么线程A的getter还是能得到一个完整的对象。而nonatomic就没有这个保证了,所以速度要比atomic快。
2)atomic可不能保证线程安全,如果线程A调用了getter,与此同时线程B和线程C都调了setter,那最后线程Aget到的值,三种都有可能:可能是B,C set之前原始的值,也可能是B set的值,也可能是C set的值。同时这个最终的值,也可能是B set的值,也可能是C set的值。要保证安全,可以使用线程锁。
11、UICollectionView自定义layout如何实现?
UICollectionViewLayoutAttributes;UICollectionViewFlowLayout。
12、用StoryBoard开发界面有什么弊端?如何避免?
用StoryBoard开发界面难以维护,如果需要改动全局的一个字体,如果是代码的话就很好办,pch或头文件中改动就好了。如果是storyboard中就需要一个一个改动很麻烦。如果storyboard中scene太多,打开storyboard会比较慢。错误定位比较困难,好多错误提示模棱两可。故大型项目时候还是采用代码比较好
13、进程和线程的区别?同步异步的区别?并行和并发的区别?
1)进程是一个内存中运行的应用程序,比如在Windows系统中,一个运行的exe就是一个进程。线程是指进程中的一个执行流程。
2)同步是顺序执行,执行完一个再执行下一个。需要等待,协调运行。异步就是彼此独立,在等待某事件的过程中继续做自己的事,不需要等待这些事件完成后再工作。
3)并发性(Concurrence):指两个或两个以上的事件或活动在同一时间间隔内发生。并发的实质是一个物理CPU(也可以多个物理CPU) 在若干道程序之间多路复用,并发性是对有限物理资源强制行使多用户共享以提高效率。
并行性(parallelism)指两个或两个以上事件或活动在同一时刻发生。在多道程序环境下,并行性使多个程序同一时刻可在不同CPU上同时执行。通俗一点并行和并发 是前者相当于三个人同时吃一个馒头,后者相当于一个人同时吃三个馒头。
区别:(并发)一个处理器同时处理多个任务和(并行)多个处理器或者是多核的处理器同时处理多个不同的任务。
14、线程间通信?
ios中线程之间通信三种方式:NSThread、GCD、NSOperation
15、GCD的一些常用的函数?(group,barrier,信号量,线程同步)
1).延迟执行任务函数:dispatch_after(.....)。
2).一次性执行dispatch_once(...)。
3).栅栏函数dispatch_barrier_async/dispatch_barrier_sync。
4).队列组的使用dispatch_group_t。
5).GCD定时器 dispatch_source_t。
16、如何使用队列来避免资源抢夺?
dispatch_barrior_async 作用是在并行队列中,等待前面两个操作并行操作完成。
17、数据持久化的几个方案
Coredata,realm(了解可查询https://www.jianshu.com/p/096bec929f2a),fmdb
18、说一下AppDelegate的几个方法?从后台到前台调用了哪些方法?第一次启动调用了哪些方法?从前台到后台调用了哪些方法?
1).当程序第一次运行并且将要显示窗口的时候执行,在该方法中我们完成的操作
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
2).程序进入后台的时候首先执行程序将要取消活跃该方法 - (void)applicationWillResignActive:(UIApplication *)application
3).该方法当应用程序进入后台的时候调用 - (void)applicationDidEnterBackground:(UIApplication *)application
4).当程序进入将要前台的时候调用 - (void)applicationWillEnterForeground:(UIApplication *)application
5).应用程序已经变得活跃(应用程序的运行状态) - (void)applicationDidBecomeActive:(UIApplication *)application
6).当程序将要退出的时候调用,如果应用程序支持后台运行,该方法被applicationDidEnterBackground:替换 - (void)applicationWillTerminate:(UIApplication *)application
19、NSCache优于NSDictionary的几点?
NSCache 是一个容器类,类似于NSDIctionary,通过key-value 形式存储和查询值,用于临时存储对象。
注意一点它和NSDictionary区别就是,NSCache 中的key不必实现copy,NSDictionary中的key必须实现copy。
NSCache中存储的对象也不必实现NSCoding协议,因为毕竟是临时存储,类似于内存缓存,程序退出后就被释放了。
20、正确编写Designated Initializer的几个原则:
可以看一篇cocoChina文章:
http://www.cocoachina.com/programmer/20140421/8204.html
21、实现description方法能取到效果:
1).NSLog(@"%@", objectA);这会自动调用objectA的description方法来输出ObjectA的描述信息.
2).description方法默认返回对象的描述信息(默认实现是返回类名和对象的内存地址)
3).description方法是基类NSObject 所带的方法,因为其默认实现是返回类名和对象的内存地址, 这样的话,使用NSLog输出OC对象,意义就不是很大,因为我们并不关心对象的内存地址,比较关心的是对象内部的一些成变量的值。因此,会经常重写description方法,覆盖description方法的默认实现。
22、objc使用什么机制管理对象内存?
通过 retainCount 的机制来决定对象是否需要释放。 每次 runloop 的时候,都会检查对象的 retainCount,如果retainCount 为 0,说明该对象没有地方需要继续使用了,可以释放掉了。
23、block的实质是什么?一共有几种block?都是什么情况下生成的?
1)Block是“带有自动变量值的匿名函数”。block对象就是一个结构体,里面有isa指针指向自己的类(global malloc stack),有desc结构体描述block的信息,forwarding指向自己或堆上自己的地址,如果block对象截获变量,这些变量也会出现在block结构体中。最重要的block结构体有一个函数指针,指向block代码块。
2)block结构体的构造函数的参数,包括函数指针,描述block的结构体,自动截获的变量(全局变量不用截获),引用到的block变量。(block对象也会转变成结构体).
3)block代码块在编译的时候会生成一个函数,函数第一个参数是前面说到的block对象结构体指针。执行block,相当于执行block里面forwarding里面的函数指针。
24、为什么在默认情况下无法修改被block捕获的变量? __block都做了什么?
1)当声明与实现一个Block时,创建的闭包会捕获在它的域中的任何涉及的变量,通过在内存中持有他们,能够在block的实现中对其进行访问。在默认情况下,任何在block的域中被捕获的变量都不能被修改,除非这个变量已被给予了__block的标志。
2)例如:__block int addtional = 5;当block捕获了一个对象时,它会对其进行retain操作,并在block代码执行完毕完release对象,这样才能保证在block执行过程中,对象不会因引用计数为0而被释放掉。block本身就是一个对象,它对其他对象的引用与一般的对象引用类似,都是需要对引用对象进行retain与release。
25、循环引用情况:例如
import "ViewController.h"
import "Student.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Student *student = [[Student alloc]init];
student.name = @"Hello World";
student.study = ^{
NSLog(@"my name is = %@",student.name);
};
}
student的study的Block里面强引用了student自身。_NSConcreteMallocBlock捕获了外部的对象,会在内部持有它。retainCount值会加一。更多例子
http://blog.csdn.net/u011146511/article/details/51273794
26、block实现界面反向传值如何实现:
1)、在第二个视图控制器的.h文件中定义声明Block属性:
// .h文件定义block
@property (nonatomic,copy) void (^ViewControllerOneBlock)
(NSString *tfText);
//.m文件
@interface ViewControllerOne ()
@property (weak, nonatomic) IBOutlet UITextField *inputTF;
@end
- (IBAction)BtnAction:(id)sender {
//判断block是否为空
if (self.ViewControllerOneBlock) {
self.ViewControllerOneBlock(self.inputTF.text);
}
[self.navigationController popViewControllerAnimated:YES];
}
2)、在第一个视图中获得第二个视图控制器,并且用第二个视图控制器来调用定义的属性:
// AViewController.m
@interface AViewController ()
@property (weak, nonatomic) IBOutlet UILabel *nextVCInfoLabel;
@end
- (IBAction)btnClicked:(id)sender {
ViewControllerOne *nextVC = [[ViewControllerOne alloc]init];
nextVC.NextViewControllerBlock = ^(NSString *tfText){
self.nextVCInfoLabel.text = tfText;
};
[self.navigationController pushViewController:nextVC animated:YES];
}
27、
objc在向一个对象发送消息时,runtime库会根据对象的isa
指针找到该对象实际所属的类,然后在该类中的方法列表以及其父类方法列表中寻找方法运行,然后在发送消息的时候,objc_msgSend方法不会返回值,所谓的返回内容都是具体调用时执行的。
28、什么时候会报unrecognized selector的异常?
当调用该对象上某个方法,而该对象上没有实现这个方法的时候, 可以通过“消息转发”进行解决。objc是动态语言,每个方法在运行时会被动态转为消息发送,即:objc_msgSend(receiver, selector)。
29、能否向编译后得到的类中增加实例变量?能否向运行时创建的类中添加实例变量?为什么?
.不能向编译后得到的类中增加实例变量;
.能向运行时创建的类中添加实例变量;
原因:因为编译后的类已经注册在 runtime 中,类结构体中的 objc_ivar_list 实例变量的链表 和 instance_size 实例变量的内存大小已经确定,同时runtime 会调用 class_setIvarLayout 或 class_setWeakIvarLayout 来处理 strong weak 引用。所以不能向存在的类中添加实例变量;运行时创建的类是可以添加实例变量,调用 class_addIvar 函数。但是得在调用objc_allocateClassPair 之后,objc_registerClassPair 之前,原因同上。
30、runtime如何实现weak变量的自动置nil?
runtime 对注册的类, 会进行布局,对于 weak 对象会放入一个 hash 表中。 用 weak 指向的对象内存地址作为 key,当此对象的引用计数为0的时候会 dealloc,假如 weak 指向的对象内存地址是a,那么就会以a为键, 在这个 weak 表中搜索,找到所有以a为键的 weak 对象,从而设置为 nil。
31、
对象方法
1> 减号 - 开头
2> 只能由对象来调用
3> 对象方法中能访问当前对象的成员变量(实例变量)
类方法
1> 加号 + 开头
2> 只能由类(名)来调用
3> 类方法中不能访问成员变量(实例变量
32、objc中向一个nil对象发送消息将会发生什么?(返回值是对象,是标量,结构体)
在 Objective-C 中向 nil 发送消息是完全有效的——只是在运行时不会有任何作用。
如果一个方法返回值是一个对象,那么发送给nil的消息将返回0(nil)。例如:Person * motherInlaw = [[aPerson spouse] mother];
1)如果 spouse 对象为 nil,那么发送给 nil 的消息 mother 也将返回 nil。
2). 如果方法返回值为指针类型,其指针大小为小于或者等于sizeof(void*),float,double,long double 或者 long long 的整型标量,发送给 nil 的消息将返回0。
3). 如果方法返回值为结构体,发送给 nil 的消息将返回0。结构体中各个字段的值将都是0。
4). 如果方法的返回值不是上述提到的几种情况,那么发送给 nil 的消息的返回值将是未定义的。
33、UITableview的优化方法(缓存高度,异步绘制,减少层级,hide,避免离屏渲染)
查看这篇博客:http://blog.csdn.net/x32sky/article/details/77253253
34、SDWebImage的缓存策略查看:
http://blog.csdn.net/u013602835/article/details/70228555
35、AFN为什么添加一条常驻线程?
如果没有常住线程的话,就会每次请求网络就去开辟线程,完成之后销毁开辟线程,这样就造成资源的浪费,而开辟一条常驻线程,就可以避免这种浪费,我们可以在每次的网络请求都添加到这条线程。
36、
_objc_msgForward是一个函数指针(和 IMP 的类型一样)
是用于消息转发的:当向一个对象发送一条消息,但它并没有实现的时候,_objc_msgForward会尝试做消息转发。
37、runloop 和线程的关系:
1)主线程的run loop默认是启动的。
iOS的应用程序里面,程序启动后会有一个如下的main()函数
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
重点是UIApplicationMain()函数,这个方法会为main thread设置一个NSRunLoop对象,这就解释了:为什么应用可以在无人操作的时候休息,需要让它干活的时候又能立马响应。
2)对其它线程来说,run loop默认是没有启动的,如果你需要更多的线程交互则可以手动配置和启动,如果线程只是去执行一个长时间的已确定的任务则不需要。
3)在任何一个 Cocoa 程序的线程中,都可以通过以下代码来获取到当前线程的 run loop 。NSRunLoop *runloop = [NSRunLoop currentRunLoop];
参考:http://blog.csdn.net/wzzvictory/article/details/9237973
38、以+ scheduledTimerWithTimeInterval...的方式触发的timer,在滑动页面上的列表时,timer会暂定回调,为什么?如何解决?
RunLoop只能运行在一种mode下,如果要换mode,当前的loop也需要停下重启成新的。利用这个机制,ScrollView滚动过程中NSDefaultRunLoopMode(kCFRunLoopDefaultMode)的mode会切换到UITrackingRunLoopMode来保证ScrollView的流畅滑动:只能在NSDefaultRunLoopMode模式下处理的事件会影响ScrollView的滑动。如果我们把一个NSTimer对象以NSDefaultRunLoopMode(kCFRunLoopDefaultMode)添加到主运行循环中的时候, ScrollView滚动过程中会因为mode的切换,而导致NSTimer将不再被调度。同时因为mode还是可定制的,所以:Timer计时会被scrollView的滑动影响的问题可以通过将timer添加到NSRunLoopCommonModes(kCFRunLoopCommonModes)来解决。代码如下:
//将timer添加到NSDefaultRunLoopMode中
[NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:@selector(timerTick:)
userInfo:nil
repeats:YES];
//然后再添加到NSRunLoopCommonModes里
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0
target:self
selector:@selector(timerTick:)
userInfo:nil
repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
39、ARC通过什么方式帮助开发者管理内存?
ARC相对于MRC,不是在编译时添加retain/release/autorelease这么简单。应该是编译期和运行期两部分共同帮助开发者管理内存。在编译期,ARC用的是更底层的C接口实现的retain/release/autorelease,这样做性能更好,也是为什么不能在ARC环境下手动retain/release/autorelease,同时对同一上下文的同一对象的成对retain/release操作进行优化(即忽略掉不必要的操作);ARC也包含运行期组件,这个地方做的优化比较复杂,但也不能被忽略。
40、BAD_ACCESS在什么情况下出现?
1)访问了悬垂指针,比如对一个已经释放的对象执行了release
2)访问已经释放对象的成员变量或者发消息。
3)死循环。
41、苹果是如何实现autoreleasepool的?
autoreleasepool 以一个队列数组的形式实现,主要通过下列三个函数完成:
objc_autoreleasepoolPush
objc_autoreleasepoolPop
objc_autorelease
看函数名就可以知道,对 autorelease 分别执行 push,和 pop 操作。销毁对象时执行release操作。
42、GCD的队列(dispatch_queue_t)分哪两种类型?
1). 串行队列Serial Dispatch Queue
2). 并行队列Concurrent Dispatch Queue
43、如何用GCD同步若干个异步调用?(如根据若干个url异步加载多张图片,然后在都下载完成后合成一张整图)
使用Dispatch Group追加block到Global Group Queue,这些block如果全部执行完毕,就会执行Main Dispatch Queue中的结束处理的block。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{ /*加载图片1 */ });
dispatch_group_async(group, queue, ^{ /*加载图片2 */ });
dispatch_group_async(group, queue, ^{ /*加载图片3 */ });
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// 合并图片
});
43、dispatch_barrier_async的作用是:
在并行队列中,为了保持某些任务的顺序,需要等待一些任务完成后才能继续进行,使用 barrier 来等待之前任务完成,避免数据竞争等问题。 dispatch_barrier_async 函数会等待追加到Concurrent Dispatch Queue并行队列中的操作全部执行完之后,然后再执行 dispatch_barrier_async 函数追加的处理,等 dispatch_barrier_async 追加的处理执行结束之后,Concurrent Dispatch Queue才恢复之前的动作继续执行。(注意:使用 dispatch_barrier_async,该函数只能搭配自定义并行队列 dispatch_queue_t 使用。不能使用:dispatch_get_global_queue,否则 dispatch_barrier_async的作用会和 dispatch_async的作用一模一样。 )
44、
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(@"1");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"2");
});
NSLog(@"3");
}
只输出:1 。发生主线程锁死。
45、app如何添加AirDrop文件分享功能
苹果在iOS 7 SDK中集成了UIActivityViewController类,可以让你很简单地就能把AirDrop功能整合进app中!
MobileVLCKit 第三方 多格式支持 视频播放!
46、内存泄露分析
1)静态分析内存泄露 使用Xcode自带的Analyze功能(Product-> Analyze)(Shift + Command + B),对代码进行静态分析,对于内存泄露(Potential Memory Leak), 未使用局部变量(dead store),逻辑错误(Logic Flaws)以及API使用问题(API-usage)等明确的展示出来
2)动态分析内存泄露 使用Xcode自带的Profile功能(Product-> Profile)(Command + i)弹出工具框,选择Leaks打开,选择运行设备点左上角的Record录制按钮,项目就会在已选好的设备上运行,并开始录制内存检测情况。选Leaks查看泄露情况,在Leaks的详细菜单Details选项里选调用树Call Tree,可查看所有内存泄露发生在哪些地方。再在右侧的齿轮设置-Call Tree-勾选Hide System Libraries,则可直接看内存泄露发生的函数名、方法名。点击函数名、方法名,可直接跳到函数方法的细节,可以看到哪一句代码出现了内存泄露,以及泄露了多少内存。
接下来就要回到Xcode,找到出现内存泄露的函数方法,仔细分析如何出现的内存泄露; 一般使用ARC,按照上面一提到的内存理解和编码习惯是不会出现内存泄露的。但我们在开发过程中,经常要使用第三方的一些类库,特别是涉及到加密的类库,用c或c++来编码的加密解密方法,会出现内存泄露。此时,我们要明白这些内存分配,需要手动释放。要一步一步看,哪里分配了内存,在使用完之后一定要记得释放free它。
47 、label 的空格属性和局部字段颜色
设置 label 的 autoresizingMask 为 NO ,可以使用空格间隔字符串!
[thirdLab setAttributedText:[self changeLabelWithText:@"点击按钮去注册"]];
//获取要调整颜色的文字位置,调整颜色 ,改变字体大小和字间距
-(NSMutableAttributedString*)changeLabelWithText:(NSString*)needText
{
NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] initWithString:needText];
[attrString addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:20] range:NSMakeRange(0,1)];
[attrString addAttribute:NSForegroundColorAttributeName value:[UIColor colorWithRed:51/255.0 green:3/255.0 blue:4/255.0 alpha:1] range:NSMakeRange(0,1)];
[attrString addAttribute:NSKernAttributeName value:@1.0f range:NSMakeRange(0, needText.length)];
[attrString addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:16] range:NSMakeRange(1,needText.length-1)];
[attrString addAttribute:NSForegroundColorAttributeName value:[UIColor blackColor] range:NSMakeRange(1,needText.length-1)];
return attrString;
}
48、过滤字符
//过滤特殊字符串,定义一个特殊字符的集合
NSCharacterSet *set = [NSCharacterSet characterSetWithCharactersInString:
@"@/:;()¥「」"、[]{}#%-*+=_\\|~<>$€^•'@#$%^&*()_+'\""];
// 过滤字符串的特殊字符
NSString *newString = [trimString stringByTrimmingCharactersInSet:set];
49、IOS应用直接退出
- (void)exitApplication {
AppDelegate *app = [UIApplication sharedApplication].delegate;
UIWindow *window = app.window;
[UIView animateWithDuration:1.0f animations:^{
window.alpha = 0;
} completion:^(BOOL finished) {
exit(0);
}];
}
50、设置滑动的时候隐藏 navigationbar
第1种:
navigationController.hidesBarsOnSwipe = Yes
第2种:
//1.当我们的手离开屏幕时候隐藏
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
if(velocity.y > 0)
{
[self.navigationController setNavigationBarHidden:YES animated:YES];
} else {
[self.navigationController setNavigationBarHidden:NO animated:YES];
}
}
velocity.y这个量,在上滑和下滑时,变化极小(小数),但是因为方向不同,有正负之分。
51、屏幕截图
// 1. 开启一个与图片相关的图形上下文
UIGraphicsBeginImageContextWithOptions(self.view.bounds.size,NO,0.0);
// 2. 获取当前图形上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 3. 获取需要截取的view的layer
[self.view.layer renderInContext:ctx];
// 4. 从当前上下文中获取图片
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
// 5. 关闭图形上下文
UIGraphicsEndImageContext();
// 6. 把图片保存到相册
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
52、导航栏、状态栏和tabbar相关
1.导航栏
//隐藏导航栏上的返回字体
//Swift
UIBarButtonItem.appearance().setBackButtonTitlePositionAdjustment(UIOffsetMake(0, -60), forBarMetrics: .Default)
//OC
[[UIBarButtonItem appearance] setBackButtonTitlePositionAdjustment:UIOffsetMake(0, -60) forBarMetrics:UIBarMetricsDefault];
//自定义导航栏的左右按钮
UIButton *searchBtn = [[UIButton alloc] initWithFrame:CGRectMake(SCREEN_WIDTH - 90, 0, 30, 44)];
UIBarButtonItem *seaBtn = [[UIBarButtonItem alloc] initWithCustomView:searchBtn];
self.navigationItem.rightBarButtonItem = seaBtn;
2.状态栏
//所有控制器状态栏字体颜色
状态栏字体颜色不同的办法
1)、在info.plist中,将View controller-based status bar appearance设为NO.
2)、在app delegate中:
[UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent;
//单独某个控制器字体颜色
3)、在个别状态栏字体颜色不一样的vc中
-(void)viewWillAppear:(BOOL)animated{
[UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleDefault;
}
3.tabbar
+ (void)load
{
// 获取当前类的tabBarItem
UITabBarItem *item = [UITabBarItem appearanceWhenContainedIn:self, nil];
// 更改tabbar 选中字体颜色
UITabBar *tabbar = [UITabBar appearanceWhenContainedIn:self, nil];
tabbar.tintColor = [UIColor orangeColor];
// 设置所有item的选中时颜色
// 设置选中文字颜色
// 创建字典去描述文本
NSMutableDictionary *attSelect = [NSMutableDictionary dictionary];
// 文本颜色 -> 描述富文本属性的key -> NSAttributedString.h
attSelect[NSForegroundColorAttributeName] = [UIColor orangeColor];
[item setTitleTextAttributes:attSelect forState:UIControlStateSelected];
// 通过normal状态设置字体大小
// 字体大小 跟 normal
NSMutableDictionary *attrNormal = [NSMutableDictionary dictionary];
// 设置字体
attrNormal[NSFontAttributeName] = [UIFont systemFontOfSize:13];
[item setTitleTextAttributes:attrNormal forState:UIControlStateNormal];
// 文字偏移量
//[item setTitlePositionAdjustment:<#(UIOffset)#>];
// icon偏移量
// item.imageInsets = UIEdgeInsetsMake(<#CGFloat top#>, <#CGFloat left#>, <#CGFloat bottom#>, <#CGFloat right#>);
}
53、去掉 tabbar 和 navgationbar 的黑线
//去掉tabBar顶部线条
CGRect rect = CGRectMake(0, 0, 1, 1);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [[UIColor clearColor] CGColor]);
CGContextFillRect(context, rect);
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self.tabBar setBackgroundImage:img];
[self.tabBar setShadowImage:img];
//[self.navigationController.navigationBar setBackgroundImage:img];
//self.navigationController.navigationBar.shadowImage = ima;
self.tabBar.backgroundColor =[UIColor color];
54、判断字符串中是否含有中文
-(BOOL)isChinese:(NSString *)str{
NSString *match=@"(^[\u4e00-\u9fa5]+$)";
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF matches %@", match];
return [predicate evaluateWithObject:str];
}
55、解决父视图和子视图的手势冲突
/** 解决手势冲突 */
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
if ([touch.view isDescendantOfView:cicView]) {
return NO;
}
return YES;
}
56、NSDate与NSString的相互转化
-(NSString *)dateToString:(NSDate *)date {
// 初始化时间格式控制器
NSDateFormatter *matter = [[NSDateFormatter alloc] init];
// 设置设计格式
[matter setDateFormat:@"yyyy-MM-dd hh:mm:ss zzz"];
// 进行转换
NSString *dateStr = [matter stringFromDate:date];
return dateStr;
}
-(NSDate *)stringToDate:(NSString *)dateStr {
// 初始化时间格式控制器
NSDateFormatter *matter = [[NSDateFormatter alloc] init];
// 设置设计格式
[matter setDateFormat:@"yyyy-MM-dd hh:mm:ss zzz"];
// 进行转换
NSDate *date = [matter dateFromString:dateStr];
return date;
}
56、删除storyboard的方法
第一、直接将工程中的storyboard直接删除掉
第二、找到plist文件,将plist文件中的Main storyboard file base name删除掉.
57、ASCII 和 NSString 的相互转换
// NSString to ASCII
NSString *string = @"A";
int asciiCode = [string characterAtIndex:0]; //65
//ASCII to NSString
int asciiCode = 65;
NSString *string =[NSString stringWithFormat:@"%c",asciiCode]; //A
58、获取当前连接的wifi名称
NSString *wifiName = @"Not Found";
CFArrayRef myArray = CNCopySupportedInterfaces();
if (myArray != nil) {
CFDictionaryRef myDict = CNCopyCurrentNetworkInfo(CFArrayGetValueAtIndex(myArray, 0));
if (myDict != nil) {
NSDictionary *dict = (NSDictionary*)CFBridgingRelease(myDict);
wifiName = [dict valueForKey:@"SSID"];
}
}
NSLog(@"wifiName:%@", wifiName);
59、苹果自带的下拉刷新方法
//设置下拉刷新 UIRefreshControl *refresh = [[UIRefreshControl alloc] init];
NSDictionary dict = @{NSForegroundColorAttributeName:[UIColor redColor]};
NSAttributedString string = [[NSAttributedString alloc] initWithString:@"帮你署最新。。" attributes:dict];
refresh.attributedTitle = string;
[self.tableView addSubview:refresh];
60、屏幕渲染--颜色渐变
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.colors = @[(__bridge id)[UIColor whiteColor].CGColor,(__bridge id)[UIColor grayColor].CGColor,(__bridge id)[UIColor whiteColor].CGColor];
gradientLayer.locations = @[@0.2,@0.65,@0.75];
gradientLayer.startPoint = CGPointMake(0, 0);
gradientLayer.endPoint = CGPointMake(1.0, 0);
gradientLayer.frame = CGRectMake(0, 100, [UIScreen mainScreen].bounds.size.width, 2);
[self.view.layer addSublayer:gradientLayer];
61、快速求和,最大值,最小值,平均值
NSArray *array = [NSArray arrayWithObjects:@"2.0", @"2.3", @"3.0", @"4.0", @"10", nil];
CGFloat sum = [[array valueForKeyPath:@"@sum.floatValue"] floatValue];
CGFloat avg = [[array valueForKeyPath:@"@avg.floatValue"] floatValue];
CGFloat max =[[array valueForKeyPath:@"@max.floatValue"] floatValue];
CGFloat min =[[array valueForKeyPath:@"@min.floatValue"] floatValue];
62、跨控制器跳转返回
for (UIViewController *controller in self.navigationController.viewControllers) {
if ([controller isKindOfClass:[@“你要返回的控制器类名” class]]) {
[self.navigationController popToViewController:controller animated:YES];
}
}
63、layer.cornerRadius 圆角流畅性的优化
第一种:CornerRadius
loginBtn.layer.cornerRadius = 10;
loginBtn.layer.shouldRasterize = YES;
loginBtn.layer.rasterizationScale = [UIScreen mainScreen].scale;
第二种:UIBezierPath 和 CAShapeLayer
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:_draw.bounds byRoundingCorners:UIRectCornerAllCorners cornerRadii:_draw.bounds.size];
CAShapeLayer *maskLayer = [[CAShapeLayer alloc]init];
// 设置大小
maskLayer.frame = _draw.bounds;
// 设置图形样子
maskLayer.path = maskPath.CGPath;
_draw.layer.mask = maskLayer;
第三种:设置上半部分圆角
_titleLabel.layer.masksToBounds = YES;
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.path = [UIBezierPath bezierPathWithRoundedRect:_titleLabel.bounds byRoundingCorners: UIRectCornerBottomLeft | UIRectCornerBottomRight cornerRadii: (CGSize){5.0f, 5.0f}].CGPath;
_titleLabel.layer.mask = maskLayer;
64、导航栏和下方视图间隔距离消失 以及 导航栏和下方视图不重叠
//不间隔
self.automaticallyAdjustsScrollViewInsets=YES;
//不重叠
self.edgesForExtendedLayout = UIRectEdgeNone
65、毛玻璃效果(ios8.0以后的版本)
UIVisualEffectView *visualEffectView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]];
visualEffectView.frame = CGRectMake(0, 0, 320*[FlexibleFrame ratio], 180*[FlexibleFrame ratio]);
visualEffectView.alpha = 1.0;
66、工作中常用的第三方
67、如何点击谷歌地图获取所在位置经纬度
68、IOS中判断两个数组是否相同
NSArray *array1 = [NSArray arrayWithObjects:@"a", @"b", @"c", nil];
NSArray *array2 = [NSArray arrayWithObjects:@"d", @"a", @"c", nil];
bool bol = false;
//创建俩新的数组
NSMutableArray *oldArr = [NSMutableArray arrayWithArray:array1];
NSMutableArray *newArr = [NSMutableArray arrayWithArray:array2];
//对数组1排序。
[oldArr sortUsingComparator:^NSComparisonResult(id obj1, id obj2){
return obj1 > obj2;
}];
//对数组2排序。
[newArr sortUsingComparator:^NSComparisonResult(id obj1, id obj2){
return obj1 > obj2;
}];
if (newArr.count == oldArr.count) {
bol = true;
for (int16_t i = 0; i < oldArr.count; i++) {
id c1 = [oldArr objectAtIndex:i];
id newc = [newArr objectAtIndex:i];
if (![newc isEqualToString:c1]) {
bol = false;
break;
}
}
}
if (bol) {
NSLog(@" ------------- 两个数组的内容相同!");
}
else {
NSLog(@"-=-------------两个数组的内容不相同!");
}
69、屏幕渲染--颜色渐变
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.colors = @[(__bridge id)[UIColor whiteColor].CGColor,(__bridge id)[UIColor grayColor].CGColor,(__bridge id)[UIColor whiteColor].CGColor];
gradientLayer.locations = @[@0.2,@0.65,@0.75];
gradientLayer.startPoint = CGPointMake(0, 0);
gradientLayer.endPoint = CGPointMake(1.0, 0);
gradientLayer.frame = CGRectMake(0, 100, [UIScreen mainScreen].bounds.size.width, 2);
[self.view.layer addSublayer:gradientLayer];
70、请求定位权限以及定位属性
_在地图页面放入下面代码:_
_locationManager=[[CLLocationManager alloc]init];
//如果没有授权则请求用户授权
if ([CLLocationManager authorizationStatus]==kCLAuthorizationStatusNotDetermined){
[_locationManager requestWhenInUseAuthorization];
}else if([CLLocationManager authorizationStatus]==kCLAuthorizationStatusAuthorizedWhenInUse){
//设置代理
_locationManager.delegate=self;
//设置定位精度
_locationManager.desiredAccuracy=kCLLocationAccuracyBest;
//定位频率,每隔多少米定位一次
CLLocationDistance distance=10.0;//十米定位一次
_locationManager.distanceFilter=distance;
//启动跟踪定位
[_locationManager startUpdatingLocation];
}
71、将几张图片合成为一张
- (UIImage *)composeWithHeader:(UIImage *)header content:(UIImage *)content footer:(UIImage *)footer{
CGSize size = CGSizeMake(content.size.width, header.size.height +content.size.height +footer.size.height);
UIGraphicsBeginImageContext(size);
[header drawInRect:CGRectMake(0,
0,
header.size.width,
header.size.height)];
[content drawInRect:CGRectMake(0,
header.size.height,
content.size.width,
content.size.height)];
[footer drawInRect:CGRectMake(0,
header.size.height+content.size.height,
footer.size.width,
footer.size.height)];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
72、按钮的选择状态及与BarButton的结合使用
self.barRightBtn = [UIButton buttonWithType:UIButtonTypeCustom];
self.barRightBtn.frame = CGRectMake(WIDTH-20, 30, 80, 30);
[self.barRightBtn setTitle:@"停止扫描" forState:UIControlStateNormal];
[self.barRightBtn setTitle:@"开始扫描" forState:UIControlStateSelected];
[self.barRightBtn setTitleColor:BLUECOLOR forState:UIControlStateNormal];
self.barRightBtn.titleLabel.font = [UIFont systemFontOfSize:18];
[[self.barRightBtn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
self.barRightBtn.selected = !self.barRightBtn.selected;
if (self.barRightBtn.selected) {
[self endScanIbeacon];
}else{
[self startScanIbecan];
}
}];
UIBarButtonItem *barBtn = [[UIBarButtonItem alloc] initWithCustomView:self.barRightBtn];
self.navigationItem.rightBarButtonItem = barBtn;
73、导航栏字体颜色改变
有时候想改变某个控制器中状态栏的字体颜色,单纯的在控制器添加 [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent],发现添加后无改变!这时候就需要设置另外一个属性!
1.在 info.plist 中,将 View controller-based status bar appearance 设为 NO;
2. 在对应控制器添加[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
74、类似于 modal 效果的弹出视图
//初始化
PopView *pop = [[PopView alloc] initWithFrame:CGRectMake(0, HEIGHT, WIDTH, HEIGHT-150)];
pop.bgImaView.image = [UIImage imageNamed:[NSString stringWithFormat:@"backgaund_%ld",(long)index]];
[self.view addSubview:pop];
//点击后frame改变,动画展示上滑 (类似于 btn 点击事件)
[UIView animateWithDuration:0.5 animations:^{
pop.frame = CGRectMake(0, 150, WIDTH, HEIGHT-150);
}];
//在点击改变frame,动画展示下滑
[UIView animateWithDuration:0.5 animations:^{
pop.frame = CGRectMake(0, HEIGHT, WIDTH, HEIGHT-150);
}];
75、设置手机声音震动
#import <AudioToolbox/AudioToolbox.h>
#import <UIKit/UIKit.h>
- (void)vibrate {
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
76、判断一个点是否在一个区域,判断一个区域是否在一个区域
1.CGRect 和 CGPoint 对比 (判断一个点是否在一个区域)
BOOL a = CGRectContainsPoint(_view.frame, point);
2.CGRect 和 CGRect 对比 (判断一个区域是否在一个区域)
BOOL b = CGRectContainsRect(_view.frame,_btn.frame)
3. CGPoint 和 CGPoint 对比 (判断两个点是否相同)
BOOL c = CGPointEqualToPoint(point1, point2);
77、图片的简单压缩
1. //背景视图 (此种压缩有白边出现)
UIImageView *bgIma = [[UIImageView alloc] initWithFrame:BOUNDS];
NSString *bgFile = [NSString stringWithFormat:@"%@/%@",[[NSBundle mainBundle] resourcePath,@"zsBg.png"]; //图片缓存处理
UIImage *image = [[UIImage alloc] initWithContentsOfFile:bgFile];
NSData *data = UIImageJPEGRepresentation(image, 1.0);
bgIma.image = [UIImage imageWithData:data];
[self addSubview:bgIma];
2.封装方法
- (UIImage *)imageWithImage:(UIImage*)image scaledToSize:(CGSize)newSize
{
// Create a graphics image context
UIGraphicsBeginImageContext(newSize);
// Tell the old image to draw in this new context, with the desired
// new size
[image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
// Get the new image from the context
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
// End the context
UIGraphicsEndImageContext();
// Return the new image.
return newImage;
}
((UIImageView *)view).image = [self imageWithImage:[UIImage imageNamed:self.notiArr[index]] scaledToSize:CGSizeMake(WIDTH-20, HEIGHT-64-10-180)] ;
78、使用Xcode查找项目中的中文字符串,以方便实现国际化的需求
1.打开”Find Navigator” (小放大镜模样 --- > 🔍)
2.切换搜索模式到 “Find > Regular Expression”
3.输入@"[^"]*[\u4E00-\u9FA5]+[^"\n]*?" (swift请去掉”@” 输入@"[^"]*[\u4E00-\u9FA5]+[^"\n]*?" )
79、判断 iOS 系统版本
_判断 iOS 系统版本大于10_
#define IOS_VERSION_10 (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_9_x_Max)?(YES):(NO)
_判断 iOS系统具体版本_
1.预编译文件(.pch文件)定义
#define iPHONEType struct utsname systemInfo;uname(&systemInfo);
引用
iPHONEType
NSString *platform = [NSString stringWithCString:systemInfo.machine encoding:NSASCIIStringEncoding];
2.[UIDevice currentDevice].systemVersion.floatValue ,例如:
if ([UIDevice currentDevice].systemVersion.floatValue < 7.0f) {
Method newMethod = class_getInstanceMethod(self, @selector(compatible_setSeparatorInset:));
// 增加Dummy方法
class_addMethod(
self,
@selector(setSeparatorInset:),
method_getImplementation(newMethod),
method_getTypeEncoding(newMethod));
}
80、判断 label 文字行数
- (NSArray *)getLinesArrayOfStringInLabel:(UILabel *)label{
NSString *text = [label text];
UIFont *font = [label font];
CGRect rect = [label frame];
CTFontRef myFont = CTFontCreateWithName(( CFStringRef)([font fontName]), [font pointSize], NULL);
NSMutableAttributedString *attStr = [[NSMutableAttributedString alloc] initWithString:text];
[attStr addAttribute:(NSString *)kCTFontAttributeName value:(__bridge id)myFont range:NSMakeRange(0, attStr.length)];
CFRelease(myFont);
CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString(( CFAttributedStringRef)attStr);
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, CGRectMake(0,0,rect.size.width,100000));
CTFrameRef frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, NULL);
NSArray *lines = ( NSArray *)CTFrameGetLines(frame);
NSMutableArray *linesArray = [[NSMutableArray alloc]init];
for (id line in lines) {
CTLineRef lineRef = (__bridge CTLineRef )line;
CFRange lineRange = CTLineGetStringRange(lineRef);
NSRange range = NSMakeRange(lineRange.location, lineRange.length);
NSString *lineString = [text substringWithRange:range];
CFAttributedStringSetAttribute((CFMutableAttributedStringRef)attStr, lineRange, kCTKernAttributeName, (CFTypeRef)([NSNumber numberWithFloat:0.0]));
CFAttributedStringSetAttribute((CFMutableAttributedStringRef)attStr, lineRange, kCTKernAttributeName, (CFTypeRef)([NSNumber numberWithInt:0.0]));
//NSLog(@"''''''''''''''''''%@",lineString);
[linesArray addObject:lineString];
}
CGPathRelease(path);
CFRelease( frame );
CFRelease(frameSetter);
return (NSArray *)linesArray;
}
81、筛选字符串(去除空格 换行符 回车符 首尾两端)
- (NSString *)returnCustomString:(NSString *)string
{
[[[[[string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] stringByReplacingOccurrencesOfString:@"/r" withString:@""] stringByReplacingOccurrencesOfString:@"/n" withString:@""] stringByReplacingOccurrencesOfString:@" " withString:@""] stringByReplacingOccurrencesOfString:@"/tab" withString:@""];
return string;
}
82、数组和字典打印输出中文
@implementation NSDictionary (LOG)
- (NSString *)descriptionWithLocale:(id)locale
{
// 1.定义一个可变的字符串, 保存拼接结果
NSMutableString *strM = [NSMutableString string];
[strM appendString:@"{\n"];
// 2.迭代字典中所有的key/value, 将这些值拼接到字符串中
[self enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
[strM appendFormat:@"\t%@ = %@,\n", key, obj];
}];
[strM appendString:@"}"];
// 删除最后一个逗号
if (self.allKeys.count > 0) {
NSRange range = [strM rangeOfString:@"," options:NSBackwardsSearch];
[strM deleteCharactersInRange:range];
}
// 3.返回拼接好的字符串
return strM;
}
@end
@implementation NSArray (LOG)
- (NSString *)descriptionWithLocale:(id)locale
{
// 1.定义一个可变的字符串, 保存拼接结果
NSMutableString *strM = [NSMutableString string];
[strM appendString:@"(\n"];
// 2.迭代字典中所有的key/value, 将这些值拼接到字符串中
[self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[strM appendFormat:@"\t%@,\n", obj];
}];
[strM appendString:@")\n"];
// 删除最后一个逗号
if (self.count > 0) {
NSRange range = [strM rangeOfString:@"," options:NSBackwardsSearch];
[strM deleteCharactersInRange:range];
}
// 3.返回拼接好的字符串
return strM;
}
@end
83、十六进制转十进制
- (NSString *)turn16to10:(NSString *)str {
if (str.length>10) {
str =[str substringFromIndex:str.length-10];
}
NSLog(@"字符=%@", str);
unsigned long long result = 0;
NSScanner *scanner = [NSScanner scannerWithString:str];
[scanner scanHexLongLong:&result];
NSString *tempInt =[NSString stringWithFormat:@"%llu", result];
if (tempInt.length>7) {
tempInt =[tempInt substringFromIndex:tempInt.length-7];
}
NSLog(@"数字=%@", tempInt);
return tempInt;
}
84、禁止苹果自带的侧滑返回功能
1.在需要禁止的控制器里面关闭侧滑返回
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// 禁用返回手势
if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
}
}
2.如果只是单个页面关闭,其他页面可以侧滑返回
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
// 开启返回手势
if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.enabled = YES;
}
}
85、合并framework
1.常规的需要合并 真机版framework 和模拟器版framework ,需要用到 lipo指令:lipo -create 真机版本路径 模拟器版本路径 -output 合并后的文件路径 (注:空格不能省去)!示例:
路径1:/Users/XXX/Library/Developer/Xcode/DerivedData/IJKMediaPlayer-giggdwtupptvcyalfbtxfhwssrix/Build/Products/Release-iphoneos/IJKMediaFramework.framework/IJKMediaFramework
路径2:/Users/XXX/Library/Developer/Xcode/DerivedData/IJKMediaPlayer-giggdwtupptvcyalfbtxfhwssrix/Build/Products/Release-iphonesimulator/IJKMediaFramework.framework/IJKMediaFramework
合并后的路径及名称:/Users/XXX/Library/Developer/Xcode/DerivedData/IJKMediaPlayer-giggdwtupptvcyalfbtxfhwssrix/Build/IJKMediaFramework
lipo -create /Users/XXX/Library/Developer/Xcode/DerivedData/IJKMediaPlayer-giggdwtupptvcyalfbtxfhwssrix/Build/Products/Release-iphoneos/IJKMediaFramework.framework/IJKMediaFramework /Users/XXX/Library/Developer/Xcode/DerivedData/IJKMediaPlayer-giggdwtupptvcyalfbtxfhwssrix/Build/Products/Release-iphonesimulator/IJKMediaFramework.framework/IJKMediaFramework -output /Users/XXX/Library/Developer/Xcode/DerivedData/IJKMediaPlayer-giggdwtupptvcyalfbtxfhwssrix/Build/IJKMediaFramework
2.报错及注意点
1)指令之间的空格不能省去
2)报错:fatal error: can't map input file
原因是因为 framework 路径格式输入错误,需要将 xxxFramework.framework 改成 xxxFramework.framework/xxxFramework
3)报错:can't move temporary file
原因是因为 合并后的 路径格式输入错误,需要在路径后面加入合并后你起的文件名称 ,/Users/river/Desktop 改成 /Users/river/Desktop/xxx.framework (xxx需要自己自定义)
86、更改 textfield 占位符 相关
UIColor *color = [UIColor whiteColor];
_userName.attributedPlaceholder = [[NSAttributedString alloc] initWithString:@"用户名" attributes:@{NSForegroundColorAttributeName: color}];
87、tableview 从第四行或者第五行显示 解决方法
在动态布局tableview行高的时候,会出现tableview cell 从第四行或者第五行开始加载,解决方案:做个判断 如果动态行高大于0 显示动态行高;如果动态行高等于0 ,默认返回一个 1或者 2值 ,举例:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
if (self.totalCellHeight > 0) {
return self.totalCellHeight;
} else{
return 1;
}
return 0;
}
88、IPV6环境搭建
89、上架审核的小注意点
1.检查全局断点是否都清除完毕;
2.检查 EditScheme 是否都是release状态;
3.检查所有数据是否包含 测试,demo 等中英文字样;
4.检查 后台模式,去除掉不需要使用的后台模式,尤其是定位相关;相关文字描述要描述清楚;
5.为以防万一,未开发的项目还是隐藏的好(看个人人品);
6.产品流程上,可点击和不可点击状态要有不同显示或者提示;
90、iBeacon初探
iBeacon初探
91、Yoga跨平台flexbox布局引擎
适合前端、IOS、安卓平台 是由facebook 开发的
Yoga跨平台flexbox布局
YogaGitHub
/*************************ios一些学习链接以及第三方库链接*********************************/
https://github.com/ChenYilong
https://github.com/facebook/pop(pop:facebook那神奇的动画引擎)
https://github.com/facebook/KVOController(KVOController:facebook出品,基于Cocoa的KVO开发,提供简单地使用方式,同时也是线程安全的。)
https://link.jianshu.com/?t=https://github.com/PSPDFKit/PSPDFKit-Demo:(PSPDFKit:十分强大的PDF开发框架,有异步加载、预览、编辑、加标注等很多功能)
https://link.jianshu.com/?t=https://github.com/kewenya/SearchCoreTest(SearchCoreTest:一个联系人搜索库,支持的搜索方式包括:用户名汉字、拼音及模糊搜索,号码搜索,最重要的是支持T9搜索)
https://link.jianshu.com/?t=https://github.com/hfossli/AGGeometryKit(AGGeometryKit:几何图形框架,把AGGeometryKit和POP结合起来使用,可实现非常棒的动态和动画)
https://github.com/honcheng/iOSPlot(实现的图标制作框架,支持折线图、饼状图等)
https://www.jianshu.com/p/4521f3d76e97
github优秀开源项目大全-iOS:
http://foggry.com/blog/2014/04/25/githubyou-xiu-xiang-mu-ios/
GitHub100个优秀IOS开源项目:
https://github.com/Aufree/trip-to-iOS/blob/master/Top-100.md
iOS开发常用三方库、插件、知名博客等等
https://github.com/Tim9Liu9/TimLiu-iOS
iOS 中应用的数据存储方式解析:
https://juejin.im/entry/58c678fd44d9040068030aba