HTTPS和HTTP的區(qū)別主要如下:
1物赶、https協(xié)議需要到ca申請證書忍些,一般免費(fèi)證書較少,因而需要一定費(fèi)用。
2仰楚、http是超文本傳輸協(xié)議沃粗,信息是明文傳輸挂绰,https則是具有安全性的ssl加密傳輸協(xié)議抛腕。
3、http和https使用的是完全不同的連接方式肝劲,用的端口也不一樣迁客,前者是80,后者是443辞槐。
4掷漱、http的連接很簡單,是無狀態(tài)的榄檬;HTTPS協(xié)議是由SSL+HTTP協(xié)議構(gòu)建的可進(jìn)行加密傳輸卜范、身份認(rèn)證的網(wǎng)絡(luò)協(xié)議,比http協(xié)議安全丙号。
IOS的ARC會導(dǎo)致的內(nèi)存泄露問題和解決方案
1.Block的循環(huán)引用
循環(huán)引用就是當(dāng)self 擁有一個block的時候先朦,在block 又調(diào)用self的方法。這個時候self強(qiáng)引用了block犬缨,而在block中使用self也會強(qiáng)引用self。這樣就會產(chǎn)生循環(huán)引用棉浸,導(dǎo)致兩個對象都得不到釋放怀薛。
self.myBlock = ^{
[self doSomething];
};
解決的方法:掐斷其中的一條強(qiáng)引用,使之變成弱引用迷郑,變成這樣枝恋,就打破了循環(huán)引用:
__weak typeof (self) weakSelf = self;
還有一些系統(tǒng)的Block,這些Block中不用做特殊處理就可以直接使用self嗡害,因?yàn)檫@些系統(tǒng)的Block由系統(tǒng)strong引用焚碌,我們的代碼沒有強(qiáng)引用它
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"Self.a %@", self.a);
});
2.NSTimer未釋放
在使用 NSTimer addtarget 時,為了防止 target 被釋放而導(dǎo)致的程序異常霸妹,timer 會強(qiáng)引用 target十电,所以這也是一處內(nèi)存泄露的隱患。解決方法是使用線程安全的MSWeakTimer,然后在dealloc中主動調(diào)用invalidate
- (void)dealloc {
[timer invalidate];
}
3.performSelector 系列
performSelector分靜態(tài)調(diào)用和動態(tài)調(diào)用鹃骂,以下這種調(diào)用 selector 的方法和直接調(diào)用 selector 基本等效台盯,執(zhí)行效果相同,不存在內(nèi)存泄露
[object methodName];
[object performSelector:@selector(methodName)];
還有一種動態(tài)綁定方式畏线,編譯器不知道即將調(diào)用的 selector 是什么静盅,不了解方法簽名和返回值,甚至是否有返回值都不懂寝殴,所以編譯器無法用 ARC 的內(nèi)存管理規(guī)則來判斷返回值是否應(yīng)該釋放蒿叠。因此,ARC 采用了比較謹(jǐn)慎的做法蚣常,不添加釋放操作栈虚,即在方法返回對象時就可能將其持有,從而可能導(dǎo)致內(nèi)存泄露史隆。在ARC下編譯會告警:
warning: performSelector may cause a leak because its selector is unknow [-Warc-performSelector-leak]
-(void)method:(SEL)selector {
[object performSelector:selector];
}
解決方式是使用函數(shù)指針魂务,顯示的聲明這個函數(shù)
IMP imp = [viewController methodForSelector:selector];
void (*func)(id, SEL) = (void *)imp;
func(viewController, selector);
4.Delegate循環(huán)引用
把delegate聲明為strong屬性導(dǎo)致了循環(huán)引用
@property (nonatomic, strong) SampleViewController *delegate;
解決方法很簡單把strong改成weak就行
@property (nonatomic, weak) SampleViewController *delegate;
5.循環(huán)未結(jié)束
如果某個ViewController中有無限循環(huán),也會導(dǎo)致即使ViewController對應(yīng)的view關(guān)掉了泌射,ViewController也不能被釋放粘姜。這種問題常發(fā)生于animation處理。
CATransition *transition = [CATransition animation];
transition.duration = 0.5;
tansition.repeatCount = HUGE_VALL;
[self.view.layer addAnimation:transition forKey:"myAnimation"];
解決辦法是熔酷,在ViewController關(guān)掉的時候孤紧,停止這個animation
-(void)viewWillDisappear:(BOOL)animated {
[self.view.layer removeAllAnimations];
}
6.非OBJC對象
ARC是自動檢測OBJC對象的,非objc對象就無能為力了拒秘,比如C或C++等号显。
C語言使用 malloc 開辟,free釋放躺酒。
C++使用new 開辟押蚤,delete釋放。
但是在ARC下羹应,不會添加非OBJC對象釋放語句揽碘,如果沒去釋放,也會造成內(nèi)存泄露园匹。
即使用了ARC雳刺,我們也要深刻理解iOS的內(nèi)存管理機(jī)制,這樣才能有效避免內(nèi)存泄露裸违。
怎么理解封裝和模塊化
1.模塊劃分
做模塊化還是要結(jié)合實(shí)際業(yè)務(wù)掖桦,對目前APP的功能做一個模塊劃分,在劃分模塊的時候還需要關(guān)注模塊之間的層級供汛。
比如說涌穆,在我們項(xiàng)目中,模塊被分成了3個層級:基礎(chǔ)層料饥、中間層蒲犬、業(yè)務(wù)層。
基礎(chǔ)層模塊比如像網(wǎng)絡(luò)框架岸啡、持久化原叮、Log、社交化分享這樣的模塊巡蘸,這一層的模塊我們可以稱之為組件奋隶,具有很強(qiáng)的可重用性。
中間層模塊可以有登錄模塊悦荒、網(wǎng)絡(luò)層唯欣、資源模塊等,這一層模塊有一個特點(diǎn)是它們依賴著基礎(chǔ)組件但又沒有很強(qiáng)的業(yè)務(wù)屬性搬味,同時業(yè)務(wù)層對這層模塊的依賴是很強(qiáng)的境氢。
業(yè)務(wù)層模塊,就是直接和產(chǎn)品需求對應(yīng)的模塊了碰纬,比如類似朋友圈萍聊、直播、Feeds流這樣的業(yè)務(wù)功能了悦析。
2.代碼隔離
模塊化首先要做的是代碼層面上獨(dú)立寿桨,任意一個基礎(chǔ)模塊都是可以獨(dú)立編譯的,底層模塊絕對不能有對上層模塊的代碼依賴强戴,還要確保未來也不會再出現(xiàn)這樣的代碼亭螟。
3.依賴管理
選擇使用CocoaPods另外一個重要原因就是骑歹,可以通過它來管理模塊間的依賴预烙,之前項(xiàng)目各個功能之所以難以復(fù)用的重要原因之一就是沒有聲明依賴
緩存問題
數(shù)據(jù)庫底層基于Sqlite。
每個數(shù)據(jù)庫表只有Key, Value兩個字段陵刹。
直接將JSON數(shù)據(jù)存儲到Value中,并設(shè)置Key默伍。
通過Key查找對應(yīng)Value數(shù)據(jù),來進(jìn)行數(shù)據(jù)增刪改查操作,并更新視圖。
1.使用SDWebImage緩存圖片衰琐。
2.使用YTKKeyValueStore更方便,也可以使用YYCache
3.使用FMDB操作數(shù)據(jù)庫炼蹦。
這三個必問項(xiàng):
自我介紹
大概介紹下你的項(xiàng)目
項(xiàng)目中的技術(shù)難點(diǎn)和問題以及怎么解決
command + R 之前發(fā)生了什么
- 預(yù)處理
- 語法和語義分析
- 生成代碼和優(yōu)化
- 匯編
- 鏈接
main函數(shù)里發(fā)生了什么
1.系統(tǒng)先讀取App的可執(zhí)行文件( Mach-0文件)羡宙,從里面獲得dyld的路徑,然后加載dyld, dyld去初始化運(yùn)行環(huán)境掐隐。
2.開啟緩存策略狗热,加載程序相關(guān)依賴庫(其中也包含我們的可執(zhí)行文件)钞馁,并對這些庫進(jìn)行鏈接,最后調(diào)用每個依賴庫的初始化方法匿刮,在這一步僧凰,runt ime被初始化。
3.當(dāng)所有依賴庫的初始化后熟丸,輪到最后-位(程序可執(zhí)行文件)進(jìn)行初始化训措,在這時 runtime會對項(xiàng)目中所有類進(jìn)行類機(jī)構(gòu)初始化,然后調(diào)用所有的load方法光羞。最后dyld返回main函數(shù)地址绩鸣, main函數(shù)被調(diào)用,我們便來到程字入口main函數(shù)纱兑。
App之間跳轉(zhuǎn)實(shí)現(xiàn)
URL Scheme方式
Universal Links方式
雖然在微信內(nèi)部開網(wǎng)頁會禁止所有的Scheme呀闻,但是iOS 9.0新增加了一項(xiàng)功能是Universal Links,使用這個功能可以使我們的App通過HTTP鏈接來啟動App潜慎。
1.如果安裝過App捡多,不管在微信里面http鏈接還是在Safari瀏覽器,還是其他第三方瀏覽器铐炫,都可以打開App垒手。
2.如果沒有安裝過App,就會打開網(wǎng)頁驳遵。
iOS ipv4和ipv6
- 首先IPv6網(wǎng)絡(luò)下只能訪問IPv6站點(diǎn)淫奔,IPv4下只能訪問IPv4站點(diǎn)。兩者在不經(jīng)過DNS轉(zhuǎn)換前提下是無法直接互相訪問的堤结;
- IPv6網(wǎng)絡(luò)下通過域名到DNS服務(wù)器唆迁,然后首先去DNS66查找v6地址,發(fā)現(xiàn)沒有則繼續(xù)到DNS44查找v4竞穷,找到后返回v4地址唐责,DNS64合成IPv6地址,在經(jīng)過NAT64地址和協(xié)議轉(zhuǎn)換瘾带,最終路由到IPv4服務(wù)器鼠哥,最終完成IPv6網(wǎng)絡(luò)下通過域名訪問只有IPv4地址的站點(diǎn)或服務(wù)器。
3.ipv4轉(zhuǎn)換成ipv6 如下:
關(guān)于ipv6審核被拒絕的問題看政,公司給的服務(wù)器地址是ip地址朴恳,不是域名,所以在蘋果審核的時候遇到了ipv6的問題
GCDAsyncSocket.h第三方
.m文件
//
// GCDAsyncSocket+GCDAsyncGetIPV6.m
//
//
// Created by xuyushiguang on 2017/1/2.
// Copyright ? 2017年 xuyushiguang. All rights reserved.
//
#import "GCDAsyncSocket+GCDAsyncGetIPV6.h"
#define IOS_CELLULAR @"pdp_ip0"
#define IOS_WIFI @"en0"
#define IOS_VPN @"utun0"
#define IP_ADDR_IPv4 @"ipv4"
#define IP_ADDR_IPv6 @"ipv6"
#import <ifaddrs.h>
#import <arpa/inet.h>
#import <net/if.h>
@implementation GCDAsyncSocket (GCDAsyncGetIPV6)
/**
1允蚣,用于ip地址ipv4和ipv6之間的轉(zhuǎn)換(如果手機(jī)連接的是ipv6的wifi可用這個方法傳入ipv4獲取ipv6地址)
2于颖,根據(jù)傳入的ip地址,獲取你想要的IP地址嚷兔,比如手機(jī)連接的是ipv6的wifi森渐,你傳入的是ipv4的地址則返回一個ipv6的地址做入,前提是你的手機(jī)鏈接的是外網(wǎng)。
3同衣,怎么判斷手機(jī)連接的是不是ipv6的Wi-Fi竟块,可根據(jù)+(BOOL)isIpv6Net這個方法判斷
@param ipAddr 傳入的ip地址,主要是傳入ipv4的ip地址
@param port 端口號耐齐,要和你傳入的ip地址的端口號一直
@return 返回和手機(jī)連接的Wi-Fi的ip類型相同的ip浪秘,比如手機(jī)連接的是ipv6的Wi-Fi,則返回一個ipv6的地址
*/
+ (NSString*)getProperIPWithAddress:(NSString*)ipAddr port:(UInt32)port
{
NSError *addresseError = nil;
NSArray *addresseArray = [GCDAsyncSocket lookupHost:ipAddr
port:port
error:&addresseError];
if (addresseError) {
NSLog(@"");
}
NSString *ipv6Addr = @"";
for (NSData *addrData in addresseArray) {
if ([GCDAsyncSocket isIPv6Address:addrData]) {
ipv6Addr = [GCDAsyncSocket hostFromAddress:addrData];
}
}
if (ipv6Addr.length == 0) {
ipv6Addr = ipAddr;
}
return ipv6Addr;
}
//判斷是否是ipv6(判斷手機(jī)連接的是不是ipv6的WiFi)
+ (BOOL)isIpv6Net{
NSArray *searchArray =
@[ IOS_VPN @"/" IP_ADDR_IPv6,
IOS_VPN @"/" IP_ADDR_IPv4,
IOS_WIFI @"/" IP_ADDR_IPv6,
IOS_WIFI @"/" IP_ADDR_IPv4,
IOS_CELLULAR @"/" IP_ADDR_IPv6,
IOS_CELLULAR @"/" IP_ADDR_IPv4 ] ;
NSDictionary *addresses = [self getIPAddresses];
__block BOOL isIpv6 = NO;
[searchArray enumerateObjectsUsingBlock:^(NSString *key, NSUInteger idx, BOOL *stop)
{
if ([key rangeOfString:@"ipv6"].length > 0 && ![[NSString stringWithFormat:@"%@",addresses[key]] hasPrefix:@"(null)"] ) {
if ( ![addresses[key] hasPrefix:@"fe80"]) {
isIpv6 = YES;
}
}
} ];
return isIpv6;
}
//獲取手機(jī)連接的ip地址(包括ipv4地址和ipv6地址)
+ (NSDictionary *)getIPAddresses
{
NSMutableDictionary *addresses = [NSMutableDictionary dictionaryWithCapacity:8];
// retrieve the current interfaces - returns 0 on success
struct ifaddrs *interfaces;
if(!getifaddrs(&interfaces)) {
// Loop through linked list of interfaces
struct ifaddrs *interface;
for(interface=interfaces; interface; interface=interface->ifa_next) {
if(!(interface->ifa_flags & IFF_UP) /* || (interface->ifa_flags & IFF_LOOPBACK) */ ) {
continue; // deeply nested code harder to read
}
const struct sockaddr_in *addr = (const struct sockaddr_in*)interface->ifa_addr;
char addrBuf[ MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) ];
if(addr && (addr->sin_family==AF_INET || addr->sin_family==AF_INET6)) {
NSString *name = [NSString stringWithUTF8String:interface->ifa_name];
NSString *type;
if(addr->sin_family == AF_INET) {
if(inet_ntop(AF_INET, &addr->sin_addr, addrBuf, INET_ADDRSTRLEN)) {
type = IP_ADDR_IPv4;
// NSLog(@"ipv4 %@",name);
}
} else {
const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6*)interface->ifa_addr;
if(inet_ntop(AF_INET6, &addr6->sin6_addr, addrBuf, INET6_ADDRSTRLEN)) {
type = IP_ADDR_IPv6;
// NSLog(@"ipv6 %@",name);
}
}
if(type) {
NSString *key = [NSString stringWithFormat:@"%@/%@", name, type];
addresses[key] = [NSString stringWithUTF8String:addrBuf];
}
}
}
// Free memory
freeifaddrs(interfaces);
}
return [addresses count] ? addresses : nil;
}
@end
iOS .m文件總結(jié)
-
.m文件是純Object-C 文件
.mm是Object-C和C++混合文件
-
.m只能調(diào)用純Object-C的類蚪缀,不能調(diào)用混合的
.mm可以調(diào)用Object-C的秫逝,也可以調(diào)用C++的
-
.m要調(diào)用混合的怎么辦?
可以
解決辦法是.h用Object-C的方式询枚,而具體實(shí)現(xiàn)用.mm的方式