银杏果

作者: muyang_js的简书 | 来源:发表于2018-11-21 11:24 被阅读36次

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.模块划分

做模块化还是要结合实际业务,对目前APP的功能做一个模块划分,在划分模块的时候还需要关注模块之间的层级。

比如说,在我们项目中,模块被分成了3个层级:基础层、中间层、业务层。

  • 基础层模块比如像网络框架、持久化、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的方式

相关文章

  • 采摘银杏,一定要注意这些

    银杏果又叫白果,民间一直都有秋食白果的风俗。又到银杏果成熟的季节,有人敲打并捡拾路边银杏树上掉下来的银杏果。虽然食...

  • (周更140)银杏果

    11.20 银杏果 女儿年幼的时候,每到秋冬季,咳嗽总会不请自来,各种偏方都试过,最终找到效果最好的是银杏果,...

  • 银杏果

    HTTPS和HTTP的区别主要如下: 1、https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。 ...

  • 银杏果

    这一年的秋,来了。 两天三夜的雨从天而降,气温一下子低到了个位数。人们将原本的单衣外面,直接套上了厚厚的棉服。北方...

  • 银杏果

    每天习惯性抬头看看它们 两个月来依然碧绿的银杏果 如果不认识银杏树 我会以为那是嫁接的一串串葡萄 我在期待什么 期...

  • 银杏果

    凉凉的小手摸着暖暖的心 心在初冬的清晨 满园的银杏果 散落在最初的墙角边 一个女孩蹲下来 轻轻拾起最小的那一枚 里...

  • 银杏果

  • 银杏果

    进入九月,秋高气爽,院子里的银杏树也挂满了银杏果。 一直没留意,原来银杏树也分雌雄,到了这个季节,雌树上挂满了金黄...

  • 银杏果

    中午吃过午饭以后 ,我和朋友一起去散步 ,中秋的太阳暖暖的 ,走在树荫下面 ,旁边是一片银杏树 ,树上挂满了银杏果...

  • 银杏果

    之前从未见过银杏树,自然也就没有见过它的果实。直到来到大学校园,这里栽植了许多银杏树,秋天银杏树的叶子金黄...

网友评论

      本文标题:银杏果

      本文链接:https://www.haomeiwen.com/subject/agbqqqtx.html