- (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;
}
複製代碼