- (BOOL)isKindOfClass:(Class)aClass
:返回一个BOOL类型的值,表示调用该方法的类是不是参数类或者继承于参数类;- (BOOL)isMemberOfClass:(Class)aClass
:返回一个BOOL类型的值,表示调用该方法的类是不是参数类;+ (BOOL)isSubclassOfClass:(Class)aClass
:返回一个BOOL类型的值,表示调用该方法的类是否是参数类的一个子类或者是这个类的自己。==
:对于基本类型,==运算符比较的是值;对于对象类型,==运算符比较的是对象的地址(便是否为同一对象);isEqual
:NSObject
方法,返回一个bool值判断两个对象是否相等。若是两个对象是相等的,那么他们必须有相同的哈希值isEqualToString
:NSString
方法,而NSString
是继承自NSObject
的,因此isEqualToString
应该是isEqual
的衍生方法,是对isEqual
的细分。速度效率上优于isEqual
。类似的还有isEqualToArray
等。load
、initialize
方法的区别是什么?load
是:根据函数地址直接调用initialize
是:经过objc_msgSend
调用load
是:runtime
加载类、分类的时候调用(只会调用一次)initialize
是:类第一次接收到消息的时候调用,每个类只会initialize
一次(父类的initialize方法可能会被调用屡次)load
是:先调用类的load
(先编译的类,有限调用load
。调用子类的load
以前,会先调用父类的load
);再调用分类的load
(先编译的分类,优先调用``load)。 *
initialize是:先初始化父类,再初始化子类(可能最终调用的是父类的
initialize`方法)。#define SIZE_ARRAY(a) (sizeof(a) / sizeof((a)[0]))
sizeof函数是求对象空间大小的函数。 arry是整个数组,arry[0]是数组中第一个元素。ios
我以前的OC底层知识点里有写。 juejin.im/post/5aa25a…算法
我以前的OC底层知识点里有写。 juejin.im/post/5aa25a…sql
HTTP 是基于 TCP/IP协议来传输信息的应用层协议。它不涉及数据包(packet)传输,主要规定了客户端和服务器之间的通讯格式,默认使用80端口。数据库
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
// 1.判断下窗口可否接收事件
if (self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01) return nil;
// 2.判断下点在不在窗口上
// 不在窗口上
if ([self pointInside:point withEvent:event] == NO) return nil;
// 3.从后往前遍历子控件数组
int count = (int)self.subviews.count;
for (int i = count - 1; i >= 0; i--) {
// 获取子控件
UIView *childView = self.subviews[i];
// 坐标系的转换,把窗口上的点转换为子控件上的点
// 把本身控件上的点转换成子控件上的点
CGPoint childP = [self convertPoint:point toView:childView];
UIView *fitView = [childView hitTest:childP withEvent:event];
if (fitView) {
// 若是能找到最合适的view
return fitView;
}
}
// 4.没有找到更合适的view,也就是没有比本身更合适的view
return self;
}
// 做用:判断下传入过来的点在不在方法调用者的坐标系上
// point:是方法调用者坐标系上的点
//- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
//{
// return NO;
//}
复制代码
//只要点击控件,就会调用touchBegin,若是没有重写这个方法,本身处理不了触摸事件
// 上一个响应者多是父控件
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
// 默认会把事件传递给上一个响应者,上一个响应者是父控件,交给父控件处理
[super touchesBegan:touches withEvent:event];
// 注意不是调用父控件的touches方法,而是调用父类的touches方法
// super是父类 superview是父控件
}
复制代码
经过响应者链条机制找到当前view所属的控制器编程
#import "UIView+Tool.h"
@implementation UIView (Tool)
//经过响应者链条获取view所在的控制器
- (UIViewController *)parentController
{
UIResponder *responder = [self nextResponder];
while (responder) {
if ([responder isKindOfClass:[UIViewController class]]) {
return (UIViewController *)responder;
}
responder = [responder nextResponder];
}
return nil;
}
@end
复制代码
#import "NSObject+Tool.h"
#import "UIView+Tool.h"
@implementation NSObject (Tool)
//经过展现window的布局视图能够获取到控制器实例对象 modal的展示方式须要取到控制器的根视图
- (UIViewController *)currentViewController
{
UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;
// modal展示方式的底层视图不一样
// 取到第一层时,取到的是UITransitionView,经过这个view拿不到控制器
UIView *firstView = [keyWindow.subviews firstObject];
UIView *secondView = [firstView.subviews firstObject];
UIViewController *vc = [secondView parentController];
if ([vc isKindOfClass:[UITabBarController class]]) {
UITabBarController *tab = (UITabBarController *)vc;
if ([tab.selectedViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController *nav = (UINavigationController *)tab.selectedViewController;
return [nav.viewControllers lastObject];
} else {
return tab.selectedViewController;
}
} else if ([vc isKindOfClass:[UINavigationController class]]) {
UINavigationController *nav = (UINavigationController *)vc;
return [nav.viewControllers lastObject];
} else {
return vc;
}
return nil;
}
@end
复制代码
// 在view中重写如下方法,其中self.button就是那个但愿被触发点击事件的按钮
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
UIView *view = [super hitTest:point withEvent:event];
if (view == nil) {
// 转换坐标系
CGPoint newPoint = [self.button convertPoint:point fromView:self];
// 判断触摸点是否在button上
if (CGRectContainsPoint(self.button.bounds, newPoint)) {
view = self.deleteButton;
}
}
return view;
}
复制代码
GCD
实现线程通讯//开启一个全局队列的子线程
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//1. 开始请求数据
//...
// 2. 数据请求完毕
//咱们知道UI的更新必须在主线程操做,因此咱们要从子线程回调到主线程
dispatch_async(dispatch_get_main_queue(), ^{
//我已经回到主线程更新
});
});
//线程延迟调用 通讯
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"## 在主线程延迟5秒调用 ##");
});
复制代码
perfermselecter
选择器实现线程通讯//数据请求完毕回调到主线程,更新UI资源信息 waitUntilDone 设置YES ,表明等待当前线程执行完毕
[self performSelectorOnMainThread:@selector(dothing:) withObject:@[@"1"] waitUntilDone:YES];
//将当前的逻辑转到后台线程去执行
[self performSelectorInBackground:@selector(dothing:) withObject:@[@"2"]];
//当咱们须要在特定的线程内去执行某一些数据的时候,咱们须要指定某一个线程操做
[self performSelector:@selector(dothing:) onThread:thread withObject:nil waitUntilDone:YES];
复制代码
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.imageView.image = image;
}];
复制代码
URL Scheme
:ios最经常使用的app通讯方式,经过openURL方式进行跳转,能够携带参数Keychain
:系统地Keychain
是一个安全的存储容器,它本质上就是一个sqllite
数据库,它的位置存储在/private/var/Keychains/keychain-2.db
,不过它所保存的全部数据都是通过加密的,能够用来为不一样的app保存敏感信息。UIPasteboard
:剪切板功能UIDocumentInteractionController
:主要是用来实现同设备上app之间的共享文档,以及文档预览、打印、发邮件和复制等功能local socket
:一个App1在本地的端口port1234进行TCP的bind和listen,另一个App2在同一个端口port1234发起TCP的connect链接,这样就能够创建正常的TCP链接,进行TCP通讯了,那么就想传什么数据就能够传什么数据了。AirDrop
:经过AirDrop实现不一样设备的App之间文档和数据的分享UIActivityViewController
:iOSSDK中封装好的类在App之间发送数据、分享数据和操做数据App Groups
:同一个开发团队开发的App之间,包括App和Extension之间共享同一份读写空间,进行数据共享。物理地址:内存单元所看到的地址。逻辑地址(虚拟地址):CPU所生成的地址。每一个进程都有本身的虚拟地址空间,不一样进程的相同的虚拟地址显然能够对应不一样的物理地址。所以地址相同(虚拟地址)而值不一样没什么奇怪。数组
循环对照ASCALL码表,A~Z为65~90,a~z为97~122。从前到后遍历字符是否在‘A’~‘Z’区间,若是是继续执行循环。若是不是,判断是否在'a'~'z'中:若是不是,继续循环;若是是,标记临界点,继续循环,判断以后的字符是否在‘A’~‘Z’区间,是返回false,不然返回true。xcode
BClass.h
中直接#import “AClass.h”
,这样作法是不合理的,由于编译时是不须要把AClass
中的所有信息编译尽可能,只须要直到该类被引入便可。因此此时使用·@class AClass
。hello.c
->hello.i
。好比#inclode
,#define
等,处理过程以下:
#define
删除,而且展开全部的宏定义。#if
,#ifdef
,#elif
,#else
,#endif
等。#include``#import
预编译指令,将被包含的文件插入到该预编译指令的位置。在这个插入的过程,是递归进行的,也就是说被包含的文件,可能还包含其余文件。//
和/***/
。hello.i -> hello.a
。
最后的俩个步骤十分依赖与目标机器,由于不一样的机器有不一样的字长,寄存器,整数数据类型和浮点数据类型等。浏览器
汇编器是将汇编代码转变成机器能够执行的命令,每个汇编语句几乎都对应一条机器指令。汇编相对于编译过程比较简单,因此根据汇编指令和机器指令的对照表一一翻译便可。汇编过程能够经过如下方式完成。-> hello.o。缓存
连接(Linking)安全
静态连接
把一个程序分红多个模块,把一个程序分割为多个模块,而后经过某种方式组合造成一个单一的程序,这就是连接。
hello.o文件,既目标文件,是以分段的形式组织在一块儿的。其简单来讲,把程序运行的地址划分为了一段一段的片断,有的片断是用来存放代码,叫代码段,这样,能够给这个段加个只读的权限,防止程序被修改;有的片断用来存放数据,叫数据段,数据常常修改,因此可读写;有的片断用来存放标识符的名字,好比某个变量 ,某个函数,叫符号表;等等。因为有这么多段,因此为了方便管理,因此又引入了一个段,叫段表,方便查找每一个段的位置。
当文件之间相互须要连接的时候,就把相同的段合并,而后把函数,变量地址修改到正确的地址上。这就是静态连接。
动态连接
咱们的想法很简单,就是当第一个例子在运行时,在内存中只有一个副本;第二个例子在发生时,只须要下载更新后的lib,而后连接,就行了。那么其实,这就是动态连接的基本思想了:把连接这个过程推迟到运行的时候在进行。在运行的时候动态的选择加载各类程序模块,这个优势,就是后来被人们用来制做程序的插件(Plug-in)。
动态连接器。它会在程序运行的时候,把程序中全部未定义的符号(好比调了动态库的一个函数,或者访问了一个变量)绑定到动态连接库中。
可能有的人,就要问了,多个程序应用一个库不会有问题么?变量冲突?是这样的。动态连接文件,把那些须要修改的部分分离了出来,与数据放在了一块儿,这样指令部分就能够保持不变,而数据部分能够在每一个进程中拥有一个副本,这种方案就是目前被称为地址无关代码(PIC,Position-independent Code)的技术。
静态库
一组相应目标文件的集合,咱们称它为库。在Linux平台上,常以.a或者.o为拓展名的文件,咱们最经常使用的C语言静态库,就位于/usr/lib/libc.a;而在Windows平台上,常以.lib为拓展名的文件,好比Visual C++附带的多个版本C/C++运行库,在VC安装的目录下的lib\目录。
一组相应目标文件的集合,咱们称它为库。在Linux平台上,动态连接文件为称为动态共享对象(DSO,Dynamic Shared Objects),简称共享对象。他们通常常以.so为拓展名的文件;而在Windows平台上,动态连接文件被称为动态连接库(DLL,Dynamical Linking Library),一般就是咱们常见的.dll为拓展名的文件。
装载(Loading)
其实目标文件,内部结构上来讲和可执行文件的结构几乎是同样的,因此通常跟可执行文件格式一块儿用一种格式进行存储。总的来讲,装载作了如下三件事情
我以前的排序算法知识点里有写。juejin.im/post/5aa78b…
提示:可用对象描述每个节点。
- (void)testTreeArithmetic{
NSDictionary * root =@{
@"type":@"addition",
@"values":@[
@{
@"type":@"addition",
@"values":@[
@{
@"type":@"number",
@"value":@"1",
},
@{
@"type":@"number",
@"value":@"2"
}
]
},
@{
@"type":@"subtraction",
@"values":@[
@{
@"type":@"multiplication",
@"values":@[
@{
@"type":@"number",
@"value":@"5"
},
@{
@"type":@"number",
@"value":@"6"
}
]
},
@{
@"type":@"number",
@"value":@"7"
}
]
},
@{
@"type":@"division",
@"values":@[
@{
@"type":@"number",
@"value":@"3"
},
@{
@"type":@"number",
@"value":@"4"
}
]
}
],
};
self.treeModel = [TreeModel mj_objectWithKeyValues:root];
NSLog(@"-------------- %f", [self calc:self.treeModel]);
}
复制代码
@interface TreeModel : NSObject
@property (nonatomic,copy) NSString * type;
@property (nonatomic,strong) NSArray * values;
@property (nonatomic,strong) NSString * value;
@end
复制代码
- (float)calc:(TreeModel *)tree{
if ([tree.type isEqualToString:@"number"]) {
return [tree.value floatValue];
}else if ([tree.type isEqualToString:@"addition"]){
float v = 0;
for (TreeModel * model in tree.values) {
v += [self calc:model];
}
return v;
}else if ([tree.type isEqualToString:@"subtraction"]){
float v =0;
for (int i = 0; i<tree.values.count; i++) {
TreeModel * model =[tree.values objectAtIndex:i];
if (i == 0) {
v = [self calc:model];
}else{
v -= [self calc:model];
}
}
return v;
}else if ([tree.type isEqualToString:@"multiplication"]){
float v = 1;
for (TreeModel * model in tree.values) {
v *= [self calc:model];
}
return v;
}else if ([tree.type isEqualToString:@"division"]){
float v = 0;
for (int i = 0; i<tree.values.count; i++) {
TreeModel * model = [tree.values objectAtIndex:i];
if (i == 0) {
v = [self calc:model];
}else
{
v /= [self calc:model];
}
}
return v;
}
return 0;
}
复制代码