银杏果

HTTPS和HTTP的区别主要如下:

1、https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。

2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。

3、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。

4、http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

IOS的ARC会导致的内存泄露问题和解决方案

1.Block的循环引用
循环引用就是当self 拥有一个block的时候,在block 又调用self的方法。这个时候self强引用了block,而在block中使用self也会强引用self。这样就会产生循环引用,导致两个对象都得不到释放。

 self.myBlock = ^{
    [self doSomething];
  };

解决的方法:掐断其中的一条强引用,使之变成弱引用,变成这样,就打破了循环引用:

__weak typeof (self) weakSelf = self;

还有一些系统的Block,这些Block中不用做特殊处理就可以直接使用self,因为这些系统的Block由系统strong引用,我们的代码没有强引用它

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 被释放而导致的程序异常,timer 会强引用 target,所以这也是一处内存泄露的隐患。解决方法是使用线程安全的MSWeakTimer,然后在dealloc中主动调用invalidate

- (void)dealloc {
   [timer invalidate];
}

3.performSelector 系列
performSelector分静态调用和动态调用,以下这种调用 selector 的方法和直接调用 selector 基本等效,执行效果相同,不存在内存泄露

[object methodName];
[object performSelector:@selector(methodName)];

还有一种动态绑定方式,编译器不知道即将调用的 selector 是什么,不了解方法签名和返回值,甚至是否有返回值都不懂,所以编译器无法用 ARC 的内存管理规则来判断返回值是否应该释放。因此,ARC 采用了比较谨慎的做法,不添加释放操作,即在方法返回对象时就可能将其持有,从而可能导致内存泄露。在ARC下编译会告警:
warning: performSelector may cause a leak because its selector is unknow [-Warc-performSelector-leak]

-(void)method:(SEL)selector {
    [object performSelector:selector];
}

解决方式是使用函数指针,显示的声明这个函数

IMP imp = [viewController methodForSelector:selector];
void (*func)(id, SEL) = (void *)imp;
func(viewController, selector);

4.Delegate循环引用
把delegate声明为strong属性导致了循环引用

@property (nonatomic, strong) SampleViewController *delegate;

解决方法很简单把strong改成weak就行

@property (nonatomic, weak) SampleViewController *delegate;

5.循环未结束
如果某个ViewController中有无限循环,也会导致即使ViewController对应的view关掉了,ViewController也不能被释放。这种问题常发生于animation处理。

CATransition *transition = [CATransition animation];
transition.duration = 0.5;
tansition.repeatCount = HUGE_VALL;
[self.view.layer addAnimation:transition forKey:"myAnimation"];

解决办法是,在ViewController关掉的时候,停止这个animation

-(void)viewWillDisappear:(BOOL)animated {
    [self.view.layer removeAllAnimations];
}

6.非OBJC对象
ARC是自动检测OBJC对象的,非objc对象就无能为力了,比如C或C++等。
C语言使用 malloc 开辟,free释放。
C++使用new 开辟,delete释放。

但是在ARC下,不会添加非OBJC对象释放语句,如果没去释放,也会造成内存泄露。

即使用了ARC,我们也要深刻理解iOS的内存管理机制,这样才能有效避免内存泄露。

怎么理解封装和模块化

1.??榛?/p>

做??榛故且岷鲜导室滴?,对目前APP的功能做一个模块划分,在划分??榈氖焙蚧剐枰刈⒛?橹涞牟慵丁?/p>

比如说,在我们项目中,??楸环殖闪?个层级:基础层、中间层、业务层。

  • 基础层??楸热缦裢缈蚣堋⒊志没?、Log、社交化分享这样的模块,这一层的??槲颐强梢猿浦榧?,具有很强的可重用性。

  • 中间层??榭梢杂械锹寄??、网络层、资源??榈龋庖徊隳?橛幸桓鎏氐闶撬且览底呕∽榧置挥泻芮康囊滴袷粜?,同时业务层对这层??榈囊览凳呛芮康?。

  • 业务层??椋褪侵苯雍筒沸枨蠖杂Φ哪?榱?,比如类似朋友圈、直播、Feeds流这样的业务功能了。

2.代码隔离

??榛紫纫龅氖谴氩忝嫔隙懒ⅲ我庖桓龌∧?槎际强梢远懒⒈嘁氲模撞隳?榫圆荒苡卸陨喜隳?榈拇胍览?,还要确保未来也不会再出现这样的代码。

3.依赖管理

选择使用CocoaPods另外一个重要原因就是,可以通过它来管理模块间的依赖,之前项目各个功能之所以难以复用的重要原因之一就是没有声明依赖

缓存问题

数据库底层基于Sqlite。
每个数据库表只有Key, Value两个字段。
直接将JSON数据存储到Value中,并设置Key。
通过Key查找对应Value数据,来进行数据增删改查操作,并更新视图。
1.使用SDWebImage缓存图片。
2.使用YTKKeyValueStore更方便,也可以使用YYCache
3.使用FMDB操作数据库。

这三个必问项:
自我介绍
大概介绍下你的项目
项目中的技术难点和问题以及怎么解决

command + R 之前发生了什么

  • 预处理
  • 语法和语义分析
  • 生成代码和优化
  • 汇编
  • 链接

main函数里发生了什么

1.系统先读取App的可执行文件( Mach-0文件),从里面获得dyld的路径,然后加载dyld, dyld去初始化运行环境。

2.开启缓存策略,加载程序相关依赖库(其中也包含我们的可执行文件),并对这些库进行链接,最后调用每个依赖库的初始化方法,在这一步,runt ime被初始化。

3.当所有依赖库的初始化后,轮到最后-位(程序可执行文件)进行初始化,在这时 runtime会对项目中所有类进行类机构初始化,然后调用所有的load方法。最后dyld返回main函数地址, main函数被调用,我们便来到程字入口main函数。

App之间跳转实现

  1. URL Scheme方式

  2. Universal Links方式

虽然在微信内部开网页会禁止所有的Scheme,但是iOS 9.0新增加了一项功能是Universal Links,使用这个功能可以使我们的App通过HTTP链接来启动App。
1.如果安装过App,不管在微信里面http链接还是在Safari浏览器,还是其他第三方浏览器,都可以打开App。
2.如果没有安装过App,就会打开网页。

iOS ipv4和ipv6

  1. 首先IPv6网络下只能访问IPv6站点,IPv4下只能访问IPv4站点。两者在不经过DNS转换前提下是无法直接互相访问的;
  2. IPv6网络下通过域名到DNS服务器,然后首先去DNS66查找v6地址,发现没有则继续到DNS44查找v4,找到后返回v4地址,DNS64合成IPv6地址,在经过NAT64地址和协议转换,最终路由到IPv4服务器,最终完成IPv6网络下通过域名访问只有IPv4地址的站点或服务器。

3.ipv4转换成ipv6 如下:

关于ipv6审核被拒绝的问题,公司给的服务器地址是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之间的转换(如果手机连接的是ipv6的wifi可用这个方法传入ipv4获取ipv6地址)
2,根据传入的ip地址,获取你想要的IP地址,比如手机连接的是ipv6的wifi,你传入的是ipv4的地址则返回一个ipv6的地址,前提是你的手机链接的是外网。
3,怎么判断手机连接的是不是ipv6的Wi-Fi,可根据+(BOOL)isIpv6Net这个方法判断
@param ipAddr 传入的ip地址,主要是传入ipv4的ip地址
@param port 端口号,要和你传入的ip地址的端口号一直
@return 返回和手机连接的Wi-Fi的ip类型相同的ip,比如手机连接的是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(判断手机连接的是不是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;
}

//获取手机连接的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文件总结

  1. .m文件是纯Object-C 文件

    .mm是Object-C和C++混合文件

  2. .m只能调用纯Object-C的类,不能调用混合的

    .mm可以调用Object-C的,也可以调用C++的

  3. .m要调用混合的怎么办?

    可以

解决办法是.h用Object-C的方式,而具体实现用.mm的方式

最后编辑于
?著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,992评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,212评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事?!?“怎么了?”我有些...
    开封第一讲书人阅读 159,535评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,197评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,310评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,383评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,409评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,191评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,621评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,910评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,084评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,763评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,403评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,083评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,318评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,946评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,967评论 2 351