OC和Swift的區(qū)別
http://www.reibang.com/writer#/notebooks/40333929/notes/103582634
遇到的問題
Block 內(nèi)調(diào)用 super 引發(fā)的循環(huán)引用
xib 用weak修飾空間
如果換成strong示血,removefromSuperView后不被釋放污尉,浪費內(nèi)存
viewController中有一個強引用的view形葬,view中有個強引用的數(shù)組的subviews剃法,當xib新增一個控件時甘有,會把控件以強引用的方式加入到subviews中;
所以,從xib添加一個控件的屬性時,用weak 也不會釋放掉奸披,因為有其他的地方強引用這個控件。自定義的控件不能使用weak涮雷,在分配完內(nèi)存后就變成了nil
TableView 復用機制:
剛開始會創(chuàng)建一個屏幕的cell阵面,上劃時,多創(chuàng)建三個,其他的cell復用已經(jīng)創(chuàng)建的cell
網(wǎng)絡(luò)請求样刷,界面消失怎么取消請求
在UIViewController的分類中交換viewWillDisappear方法嗽交,添加NSURLSessionDataTask的屬性task
在viewWillDisappear方法中調(diào)用task 的cancel方法
#import "UIViewController+Category.h"
#import <objc/runtime.h>
static void *dataTaskKey;
@implementation UIViewController (Category)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
FSSwizzleMethod([self class], @selector(viewWillDisappear:), @selector(fs_viewWillDisappear:));
});
}
- (void)fs_viewWillDisappear:(BOOL)animated {
[self.dataTask cancel];
[self fs_viewWillDisappear:animated];
}
- (NSURLSessionDataTask *)dataTask {
return objc_getAssociatedObject(self, &dataTaskKey);
}
- (void)setDataTask:(NSURLSessionDataTask *)dataTask {
objc_setAssociatedObject(self, &dataTaskKey, dataTask, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
void FSSwizzleMethod(Class cls, SEL originalSelector, SEL swizzledSelector) {
Method originalMethod = class_getInstanceMethod(cls, originalSelector);
Method swizzledMethod = class_getInstanceMethod(cls, swizzledSelector);
BOOL didAddMethod = class_addMethod(cls, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
class_replaceMethod(cls, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
@end
copy 修飾string,array颂斜,dictionary ; strong修飾mutableString拾枣,mutableArray沃疮, mutableDictionary
1)如果用strong修飾string,發(fā)生淺拷貝梅肤, 對mutableString 賦值給string司蔬, mutableString修改值會互相影響,出現(xiàn)臟數(shù)據(jù)姨蝴; copy修飾string俊啼,mutableString復制給string,會開辟新的內(nèi)存左医,將內(nèi)容copy到內(nèi)存中授帕,發(fā)生深拷貝,互不影響
2)用copy修飾mutableString浮梢, 初始化mutableString是不可變類型跛十,對它賦值會copy一份不可變的空間,對mutableString appending修改會崩潰秕硝,用strong不會芥映,屬性的類型是在運行時決定的,并不是@property申明什么類型就是什么類型
3)copy修飾詞起作用是在setter方法中發(fā)生的远豺,
copy,strong詳解
@property (nonatomic, strong) NSString *str_strong;
@property (nonatomic, copy) NSString *str_copy;
@property (nonatomic, copy) NSMutableString *mutableStr_copy;
@property (nonatomic, strong) NSMutableString *mutableStr_strong;
NSMutableString *mutableStr1 = [@"222" mutableCopy];
self.str_strong = mutableStr1;
self.str_copy = mutableStr1;
[mutableStr1 appendString:@"111"];
NSLog(@"----str_copy====%@\n -----str_strong====%@",self.str_copy, self.str_strong);
// 2022-11-18 10:00:35.256711+0800 OCProject[26849:383260] ----str_copy====222
// -----str_strong====222111
NSString *str1 = @"222";
self.str_strong = str1; // 和str1同地址
self.str_copy = str1;// 和str1同地址
str1 = @"1111"; // 重新分配一個空間
// str_copy====222
// -----str_strong====222
NSString *str1 = @"222";
self.mutableStr_copy = str1;
self.mutableStr_strong = str1;
[self.mutableStr_copy appendString:@"aaa"]; // 崩潰self.mutableStr_copy不可變
[self. mutableStr_strong appendString:@"bbb"]; // 崩潰self.mutableStr_strong不可變
self.mutableStr_copy = mutableStr1;
self.mutableStr_strong =mutableStr1
[self. mutableStr_strong appendString:@"bbb"]; // @"222bbb" 和mutableStr1同地址奈偏,任意一處改動其他也跟蹤改動
[self.mutableStr_copy appendString:@"aaa"]; // self.mutableStr_copy不可變,崩潰
self.mutableStr_copy = [@"222" copy];
self.mutableStr_strong = [@"222" copy];
[self. mutableStr_strong appendString:@"bbb"]; // 崩潰self.mutableStr_copy不可變
[self.mutableStr_copy appendString:@"aaa"];// 崩潰self.mutableStr_strong不可
_str_strong = str1;
_str_copy = str1;
_str_strong = mutableStr1;
_str_copy = mutableStr1;
_mutableStr_strong = str1;
_mutableStr_copy = str1;
[_mutableStr_strong appendString:@"aaa"]; //崩潰
[_mutableStr_copy appendString:@"aaa"];// 崩潰
_str_strong = mutableStr1;
_str_copy = mutableStr1;
_mutableStr_strong = mutableStr1;
_mutableStr_copy = mutableStr1;
[_mutableStr_strong appendString:@"aaa"];
[_mutableStr_copy appendString:@"aaa"];
// _str_strong躯护、_str_copy惊来、mutableStr、_mutableStr_copy棺滞、_mutableStr_strong都是 10x00006000006a6a30 @"222aaaaaa" 同地址唁盏,copy是發(fā)生在set方法中的,_下劃線取值不調(diào)用set检眯,get方法
appdelegate過大怎么處理
1厘擂、使用Notification監(jiān)聽各種場景
2、使用ModuleManager锰瘸,在ModuleManager實現(xiàn)遵守UIAppdelegate方法刽严,轉(zhuǎn)發(fā)到實現(xiàn)代理方法的各個模塊
6、組件化
7、長連接
http://www.reibang.com/writer#/notebooks/53203941/notes/107600812
拆包:一個head對應對一個body舞萄,head中存放body的數(shù)據(jù)長度
解析:protobuf
重連機制:
心跳包:
8眨补、計時器的種類
NSTimer、CADisplayLink倒脓、dispatch_source_t
NSTimer
1撑螺、存在延遲
不管是一次性的還是周期性的timer的實際觸發(fā)事件的時間,都會與所加入的RunLoop和RunLoop Mode有關(guān)崎弃,如果此RunLoop正在執(zhí)行一個連續(xù)性的運算甘晤,timer就會被延時出發(fā)。重復性的timer遇到這種情況饲做,如果延遲超過了一個周期线婚,則會在延時結(jié)束后立刻執(zhí)行,并按照之前指定的周期繼續(xù)執(zhí)行盆均。
不適用是要置為nil塞弊,防止循環(huán)引用
dispatch_source_t
1、時間準確泪姨,需要將dispatch_source_t timer設(shè)置為成員變量游沿,不然會立即釋放
CADisplayLink
_displaylinkTimer = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleDisplayLink:)];
[_displaylinkTimer addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
屏幕刷新時調(diào)用CADisplayLink是一個能讓我們以和屏幕刷新率同步的頻率將特定的內(nèi)容畫到屏幕上的定時器類。CADisplayLink以特定模式注冊到runloop后肮砾,每當屏幕顯示內(nèi)容刷新結(jié)束的時候奏候,runloop就會向CADisplayLink指定的target發(fā)送一次指定的selector消息, CADisplayLink類對應的selector就會被調(diào)用一次唇敞。所以通常情況下蔗草,按照iOS設(shè)備屏幕的刷新率60次/秒
iOS設(shè)備的屏幕刷新頻率是固定的,CADisplayLink在正常情況下會在每次刷新結(jié)束都被調(diào)用疆柔,精確度相當高咒精。但如果調(diào)用的方法比較耗時,超過了屏幕刷新周期旷档,就會導致跳過若干次回調(diào)調(diào)用機會模叙。如果CPU過于繁忙,無法保證屏幕60次/秒的刷新率鞋屈,就會導致跳過若干次調(diào)用回調(diào)方法的機會范咨,跳過次數(shù)取決CPU的忙碌程度。
但是新設(shè)備屏幕刷新率是動態(tài)的厂庇,不再是固定的60fps
get post區(qū)別
https://www.cnblogs.com/wayaoyao/p/10960379.html
1渠啊、get請求參數(shù)再url中,長度限制2KB权旷,可見替蛉,post在body中,不限制、不可見
2躲查、get是請求服務(wù)器數(shù)據(jù)它浅,post是發(fā)送數(shù)據(jù)到服務(wù)器,會修改服務(wù)器數(shù)據(jù)
3镣煮、get只支持ASCII字符姐霍,post沒有字符類型限制
4、post的缺點:速度比get傳輸慢典唇,get的效率更高
OC中使用字符串枚舉使用:NS_STRING_ENUM
.h 文件中 -------------
typedef NSString *KLTypeStr NS_STRING_ENUM;
FOUNDATION_EXPORT KLTypeStr const KLTypeStringRed;
FOUNDATION_EXPORT KLTypeStr const KLTypeStringGreen;
FOUNDATION_EXPORT KLTypeStr const KLTypeStringOrange;
.m 文件中 --------------
NSString * const KLTypeStringRed = @"紅色";
NSString * const KLTypeStringGreen = @"綠色";
NSString * const KLTypeStringOrange = @"橘色";
webSocket降頻镊折,重連機制
降頻:在buffer中每次讀取成功后,接著下一次讀取
重連機制:
重連的時機:1蚓聘、心跳包接收超時2、網(wǎng)絡(luò)環(huán)境變化盟劫,當網(wǎng)絡(luò)變化連接并不是立即的就快不可以用夜牡,所以切換網(wǎng)絡(luò)后立即發(fā)送一個心跳包測試連接是否可用
如果安裝2n次方的時間間隔重連,重連5次后仍然失敗就放棄重連
登錄后才能跳轉(zhuǎn)一個界面實現(xiàn)
1侣签、在UIViewController分類中添加block
//.h
typedef BOOL(^NavigationControllerShouldForbiddenPushIntoCurrentVC)(UINavigationController *naviVC);
@property (nonatomic, copy) NavigationControllerShouldForbiddenPushIntoCurrentVC navigationControllerShouldForbiddenPushIntoCurrentVC;
//.m 在分類中添加屬性
YYSYNTH_DYNAMIC_PROPERTY_OBJECT(navigationControllerShouldForbiddenPushIntoCurrentVC, setNavigationControllerShouldForbiddenPushIntoCurrentVC, RETAIN_NONATOMIC, NavigationControllerShouldForbiddenPushIntoCurrentVC)
自定義UINavigationController子類:FSNavigationController.m
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
if (viewController.navigationControllerShouldForbiddenPushIntoCurrentVC) {
shouldForbidden = viewController.navigationControllerShouldForbiddenPushIntoCurrentVC(self);
}
shouldForbidden = true 就不跳轉(zhuǎn)
使用的UIViewController種初始化方法實現(xiàn)block塘装,并返回是禁止跳轉(zhuǎn),當禁止跳轉(zhuǎn)時在block中執(zhí)行登錄方法影所,在登錄成功的回到中push self
- (instancetype)init
{
self = [super init];
if (self) {
@weakify(self);
self.navigationControllerShouldForbiddenPushIntoCurrentVC = ^BOOL(UINavigationController *naviVC) {
@strongify(self);
BOOL shouldForbidden = !FSUser.user.information.isLogin;
if (shouldForbidden) {
[naviVC loginCompletion:^(BOOL didLogin) {
[naviVC pushViewController:self animated:YES];
}];
}
return shouldForbidden;
};
}
return self;
}
避免button重復點擊
使用runtime 解決按鈕重復點擊的問題
創(chuàng)建button的分類蹦肴,在分類中交換- (void)sendAction:(SEL)action to:(nullable id)target forEvent:(nullable UIEvent *)event;
在自己實現(xiàn)的sendaction方法中判斷是否要執(zhí)行sendaction方法,如果執(zhí)行猴娩,disable參數(shù)設(shè)置為YES阴幌,通過[self performSelector:@selector(setIgnoreEvent:) withObject:@(NO) afterDelay:EVENTINTERVAL];
調(diào)用disable的set方法,隔一段時間設(shè)置為NO卷中,
WKWebView緩存
(https://juejin.cn/post/6844904153810993165#heading-4)
同一個請求連續(xù)發(fā)送兩個矛双,后發(fā)送的先到,獲取的事先發(fā)送的數(shù)據(jù)蟆豫,
1议忽、 按鈕防止重復點擊,0.5s的間隔
2十减、只允許最新的請求發(fā)送栈幸,老的請求都取消
:后發(fā)送的請求和未返回的請求重復時,就取消之前的request
優(yōu)點:多次請求帮辟,保證了最新的請求發(fā)出速址,用戶拿到的一定是最新的數(shù)據(jù),類似防抖由驹。
缺點:
同時可能后臺已經(jīng)處理請求到一半了壳繁,然后請求被取消了,馬上又進來一個請求,可能會造成效率不會太高闹炉。
3蒿赢、只允許最老的請求發(fā)送,新的請求都取消
取消后來重復的請求渣触,前面的請求沒有返回羡棵,都不讓發(fā)送,有多個重復請求嗅钻,前端確保只發(fā)送一個皂冰。
優(yōu)點:多次請求,保證了最老的請求發(fā)出养篓,服務(wù)器壓力小秃流。
缺點:用戶拿到的可能不是最新的數(shù)據(jù)。
4柳弄、允許多個請求發(fā)送舶胀,有一個請求成功,取消其他還在處理的請求
優(yōu)點:能保證請求至少返回一個碧注,尤其是當單個失敗的可能性比較大愕够,允許發(fā)出多個疫稿,那么用戶頻繁操作,成功的概率就更大。
缺點:
①. 用戶拿到的數(shù)據(jù)不能保證是最新的凯亮。
②. 能否成功取消晒衩,由網(wǎng)絡(luò)速度和這這部分代碼執(zhí)行速度決定增淹,網(wǎng)絡(luò)比代碼快膛堤,比如網(wǎng)絡(luò) 10 毫秒內(nèi)返回,可能無法請求壳影,原因是第一個網(wǎng)絡(luò)成功了耿导,第二個請求還沒發(fā)出,即網(wǎng)絡(luò)返回了态贤,判斷重復的函數(shù)還沒執(zhí)行舱呻。
當 url、method悠汽、參數(shù)一樣箱吕,就是相同請求。
同一個類多個category同時交換一個方法柿冲,執(zhí)行順序如何茬高?(包括交換后方法同名,交換后方法不同名)
例如有兩個分類
結(jié)論:
1.如果交換后方法同名假抄,最后只運行類中的方法怎栽,兩次交換還原了SEL和IMP
2.如果交換后方法不同名丽猬,會倒敘執(zhí)行文件的方法,如上:先執(zhí)行2->1->宿主類
方法執(zhí)行的順序:后編譯的先執(zhí)行
APP啟動時代理的執(zhí)行方法
func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
print("第一步");
return true
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
print("第二步");
return true
}
// 先WillEnterForeground 后DidBecomeActive
func applicationWillEnterForeground(_ application: UIApplication) {
print("第三步");
}
func applicationDidBecomeActive(_ application: UIApplication) {
print("第四步");
}
// 先WillResignActive 后DidEnterBackground
func applicationWillResignActive(_ application: UIApplication) {
print("11111111");
}
func applicationDidEnterBackground(_ application: UIApplication) {
print("11111111");
}
func applicationWillTerminate(_ application: UIApplication) {
print("11111111");
}
多個網(wǎng)絡(luò)請求熏瞄,UI只刷新一次
http://www.reibang.com/writer#/notebooks/53203941/notes/107684334
利用dispatch_group脚祟,dispatch_group_enter和dispatch_group_leave控制group中任務(wù)的數(shù)量,當group任務(wù)都執(zhí)行完畢時强饮,執(zhí)行dispatch_group_notify的任務(wù)
在dispatch_group_notify中 在主線程中執(zhí)行UI刷新
弱網(wǎng)環(huán)境長連接丟包
1由桌、弱網(wǎng)優(yōu)化:DNS query 是不用默認的,自己搭建httpDNS邮丰,查詢IP行您,緩存IP,避免DNS劫持和故障
2剪廉、TCP娃循,TLS預先建立連接和緩存,
3斗蒋、檢測弱網(wǎng)環(huán)境捌斧,使用QUIC協(xié)議
2、丟包重傳:模仿TCP重傳機制吹泡,設(shè)計應答機制骤星,未收到確認就丟包了经瓷,重傳爆哑,連續(xù)重傳失敗就等網(wǎng)絡(luò)環(huán)境好了再嘗試
數(shù)據(jù)持久化方案
https://zhuanlan.zhihu.com/p/468264281
kvo使用場景以及 影響上架
監(jiān)聽屬性的變化
監(jiān)聽不存在的key會崩潰
H5登錄自動登錄狀態(tài)
NSString *scriptCookie = [NSString stringWithFormat:
@"document.cookie = 'token=%@'",
user.information.token ?: @"" ];
WKUserContentController *userContentController = WKUserContentController.new;
[userContentController addUserScript:[[WKUserScript alloc] initWithSource:scriptCookie
injectionTime:WKUserScriptInjectionTimeAtDocumentStart
forMainFrameOnly:NO]];
webViewConfig.userContentController = userContentController;
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:req];
request.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
// JS注入的Cookie,比如PHP代碼在Cookie容器中取是取不到的 所以cookie種兩次
[request setValue:[NSString stringWithFormat:@"%@=%@", @"token", [FSUser user].information.token ?: @""] forHTTPHeaderField:@"Cookie"];
oom解決方案
頭條抖音如何實現(xiàn)OOM崩潰率下降50%+
百度APP iOS端內(nèi)存優(yōu)化實踐-內(nèi)存管控方案
卡頓監(jiān)控
1舆吮、子線程監(jiān)控主線程runloop周期的時間
2揭朝、ping主線程,是否有回應
3色冀、監(jiān)控FPS
nonatomic線程安全問題
復現(xiàn)場景
@property (nonatomic, copy) NSString *testStr;
dispatch_queue_t queue = dispatch_queue_create("11111", DISPATCH_QUEUE_CONCURRENT);
for (int i = 0; i < 100000; i++) {
dispatch_async(queue, ^{
self.testStr = [NSString stringWithFormat:@"%d", i * i * i];
NSLog(@"---%@",self.testStr);
});
}
問題分析http://www.reibang.com/p/a39b8c8ed3b1
若在MRC 下潭袱,屬性name的set方法如下:
-(void)setName:(NSString *)name{
if (_name != name) {
[_name release];
[name retain];
_name = name;
}
}
一個線程release時,其他線程已經(jīng)把name锋恬,release了
點擊home鍵做了什么
http://www.manongjc.com/detail/53-bdwmccdgyqbaeio.html
如何深拷貝一個數(shù)組屯换,數(shù)組里面是對象
viewDidLoad的調(diào)用時機
view加載到內(nèi)存時
[ViewController的生命周期](https://blog.csdn.net/chabuduoxs/article/details/120333278)
loadView->viewDidLoad-> viewWillAppear -> viewWillLayoutSubviews -> viewDidLayoutSubviews -> viewDidAppear -> viewWillDisappear -> viewDidDisappear-> dealloc->
view的生命周期
init(frame: CGRect) ->willMove(toSuperview ->didMoveToSuperview ->willMove(toWindow -> didMoveToWindow-> layoutSubviews-> draw(_ rect
執(zhí)行remove操作 ->willMove(toSuperview->willMove(toWindow->didMoveToWindow->didMoveToSuperview
->dealloc
如何監(jiān)測啟動時間
linkmap文件的作用
runloop防崩,設(shè)置的時間是用來干啥
vc的生命周期
如何設(shè)計一個日志系統(tǒng)
死鎖的產(chǎn)生
1与学、互斥條件:同一份資源不能被多個線程同時持有彤悔,只能等持有的線程釋放后,才能被其他線程訪問
2索守、持有并等待:當線程A持有資源A后晕窑,等待訪問資源B時,持有的資源A不會被釋放
3卵佛、不可剝奪:線程A為釋放資源A前杨赤,其他線程只能等待資源A被釋放敞斋,不能剝奪線程A持有的資源
4、環(huán)路等待:線程A持有資源A并等待訪問資源B疾牲,線程B持有資源B并等待資源A植捎,出現(xiàn)了環(huán)路等待
打破這四個條件中的一個,即可避免死鎖说敏,一般破壞環(huán)路等待條件
斷點續(xù)傳
斷點續(xù)傳主要依賴于 HTTP 頭部定義的 Range 來完成鸥跟。有了 Range,應用可以通過 HTTP 請求獲取失敗的資源盔沫,從而來恢復下載該資源医咨。當然并不是所有的服務(wù)器都支持 Range,但大多數(shù)服務(wù)器是可以的架诞。Range 是以字節(jié)計算的拟淮,請求的時候不必給出結(jié)尾字節(jié)數(shù),因為請求方并不一定知道資源的大小谴忧。
斷點續(xù)傳原理淺析
提升網(wǎng)絡(luò)請求速率
國外網(wǎng)絡(luò)被墻的原理
DNS污染:有意或無意進行的域名服務(wù)器分組很泊,將域名指向錯誤的IP地址。
[VPN原理](http://www.jsxyy.com.cn/voddetail/199409.html)
VPN:(Virtual Private Network)沾谓,學名虛擬專用網(wǎng)絡(luò)
通過數(shù)據(jù)加密技術(shù)封裝出來的一條虛擬數(shù)據(jù)通信隧道委造,實際上它借用的還是互聯(lián)網(wǎng)上的公共鏈路。VPN會對你和公司之間傳遞的數(shù)據(jù)進行加密處理均驶,加密后的數(shù)據(jù)會在一條專用的數(shù)據(jù)鏈路上進行安全傳輸昏兆,如同架設(shè)了一個專用網(wǎng)絡(luò)一樣。所以VPN稱為虛擬專用網(wǎng)絡(luò)妇穴。
當開啟VPN后爬虱,你訪問公司內(nèi)網(wǎng)的辦公網(wǎng)站時,不再直接訪問公司內(nèi)網(wǎng)的服務(wù)器腾它,而是去訪問VPN服務(wù)器跑筝,并給VPN服務(wù)器發(fā)一條指令“我要訪問辦公網(wǎng)站”。VPN服務(wù)器接到指令后瞒滴,代替你去訪問辦公網(wǎng)站曲梗,收到公司辦公網(wǎng)站的內(nèi)容后,再通過“秘密隧道”將內(nèi)容回傳給你妓忍,這樣你就通過VPN成功訪問到你需要的內(nèi)網(wǎng)資源啦
字典的底層數(shù)據(jù)結(jié)構(gòu)
NSDictionary(字典)是使用hash表來實現(xiàn)key和value之間的映射和存儲的
dictionary內(nèi)部使用了兩個指針數(shù)組分別來保存keys和value虏两,已知的是dictionary采用的是連續(xù)存儲的方式存儲鍵值對,key哈希出來的數(shù)組下標地址单默,同樣這個地址對應到values數(shù)組的下標碘举,就是匹配到的值。因此keys和values這兩個數(shù)組的長度一致才能保證匹配到數(shù)據(jù)搁廓。內(nèi)部結(jié)構(gòu)還有個_capacity表示當前通列表的擴充閥域 引颈,當count數(shù)量達到這個長度就擴容
NSDictionary設(shè)置的key和value耕皮,key值會根據(jù)特定的hash函數(shù)算出建立的空桶數(shù)組,keys和values同樣多蝙场,然后存儲數(shù)據(jù)的時候凌停,根據(jù)hash函數(shù)算出來的值,找到對應的index下標售滤,如果下標已有數(shù)據(jù)罚拟,開放定址法后移動插入,如果空桶數(shù)組到達數(shù)據(jù)閥值完箩,這個時候就會把空桶數(shù)組擴容赐俗,然后重新哈希插入。這樣把一些不連續(xù)的key-value值插入到了能建立起關(guān)系的hash表中弊知,當我們查找的時候阻逮,key根據(jù)哈希值算出來index,直接index訪問hash表keys和hash表values秩彤,這樣查詢速度就可以和連續(xù)線性存儲的數(shù)據(jù)一樣接近O(1)了叔扼,只是占用空間有點大,性能就很強悍漫雷。
crash的抓取
1瓜富、Xcode->windows->Devices and simulators->選擇對應的手機,刷新view device logs ->找到對應時間的crash日志導出到本地
2降盹、手機設(shè)置->隱私->分析與改進->分析數(shù)據(jù)
3与柑、異常捕獲和日志上傳
NSMutableArray的數(shù)據(jù)結(jié)構(gòu)
循環(huán)列表,從頭或者尾做刪除澎现,添加的操作仅胞,消耗較小每辟,有offset 偏移量來計算真實的下標剑辫,避免了從頭或者尾部刪除、添加操作造成的數(shù)組元素重新排列移動
NSMutableArray詳解
循環(huán)中異步賦值
例子
tagged pointer沒有release和retain操作 不會崩潰渠欺,數(shù)據(jù)大時會崩潰
base64
base64編碼后會變大:轉(zhuǎn)換到ASCII碼后妹蔽,會講6位 一個單位,前面兩位補0挠将,作為1個字節(jié)
https://blog.csdn.net/JackieDYH/article/details/122558936
為什么使用base64編碼:二進制不兼容胳岂。某些二進制值,在一些硬件上舔稀,比如在不同的路由器乳丰,老電腦上,表示的意義不一樣内贮,做的處理也不一樣产园。同樣汞斧,一些老的軟件,網(wǎng)絡(luò)協(xié)議也有類似的問題什燕。但是萬幸粘勒,Base64使用的64個字符,經(jīng)ASCII/UTF-8編碼后在大多數(shù)機器屎即,軟件上的行為是一樣的庙睡。
網(wǎng)絡(luò)請求封裝
1、制定請求參數(shù)和響應數(shù)據(jù)對象的類
2技俐、傳入headFiled值
3乘陪、調(diào)用AFNetworking的網(wǎng)絡(luò)請求,生成task雕擂,執(zhí)行resume發(fā)起請求
4暂刘、以請求為value,URL為key放入到字典中捂刺,取消同一個URL的上一個網(wǎng)絡(luò)請求
5谣拣、根據(jù)網(wǎng)絡(luò)請求結(jié)果處理成功失敗的場景
成功:根據(jù)傳入的響應數(shù)據(jù)的類,進行數(shù)據(jù)解析族展,并將數(shù)據(jù)緩存森缠,下次網(wǎng)絡(luò)請求可以讀取本地數(shù)據(jù)
動圖加載
1、將data轉(zhuǎn)化為imagesource仪缸,獲取到imagesource的播放次數(shù)贵涵,圖片個數(shù),播放間隔
2恰画、利用CADisplayLink播放加載播放的image宾茂,調(diào)用setNeedsDisplay方法
在displayLayer中對content賦值image