为了解决了那一个莫名奇妙的难题,然后终于化解了难点

为了解决了这些莫名奇妙的问题,为了解决了这些莫名奇妙的问题

前言:

话说明儿晚上要么今儿早上,写了一篇:叙述Sagit.Framework消除:双向引用导致的IOS内部存款和储蓄器泄漏(上)

小说写到末了时,多了诸多莫名奇妙的题材!!!

为了缓解了这么些莫名奇妙的题材,作者又战斗了24小时〜〜〜

下一场终于化解了难点,原来是IOS的隐藏性Bug,只想恨恨的说一声fuck~~~

前言:

话说明儿晚上要么明早,写了一篇:叙述Sagit.Framework化解:双向引用导致的IOS内部存款和储蓄器泄漏(上)

作品写到最后时,多了好多莫名奇妙的题材!!!

为了缓解了这么些莫名奇妙的题材,作者又战斗了24时辰〜〜〜

下一场终于解决了难点,原来是IOS的隐藏性Bug,只想恨恨的说一声fuck~~~

逸事出自:

传说是那般的,为了处理内存释放的难题,平常人的思索,都是给指标的dealloc扩充日志输出。

于是,UIView、UIViewController和八个Sagit定义的基类S电视iew、STController,任其自然就拉长了如此一行代码:

-(void)dealloc{
    NSLog(@"UIView relase -> %@", [self class]);
}

然后就经过输出的日志,旁观该措施被执行与否,来承认对象是或不是健康被假释。

在各类强引用、弱引用、循环引用、先强后弱引用的坑里跳来跳去后,终于祭出了宏观的杀招,来拍卖那么些难题:

-(id)key:(NSString *)key
{
    id value=[self.keyValue get:key];
    if(value==nil)
    {
        value=[self.keyValueWeak get:key];
    }
    return value;
}
-(UIView*)key:(NSString *)key valueWeak:(id)value
{
    [self.keyValueWeak set:key value:value];
    return self;
}
-(UIView*)key:(NSString *)key value:(id)value
{
    [self.keyValue set:key value:value];
    return self;
}
-(NSMapTable*)keyValueWeak
{
    NSMapTable *kv=[self.keyValue get:@"keyValueWeak"];
    if(kv==nil)
    {
        kv=[NSMapTable mapTableWithKeyOptions:NSMapTableWeakMemory valueOptions:NSMapTableWeakMemory];
        [self.keyValue set:@"keyValueWeak" value:kv];
    }
    return kv;
//    NSMapTable *kv= (NSMapTable*)objc_getAssociatedObject(self, &keyValueWeakChar);
//    if(kv==nil)
//    {
//        kv=[NSMapTable mapTableWithKeyOptions:NSMapTableWeakMemory valueOptions:NSMapTableWeakMemory];
//        objc_setAssociatedObject(self, &keyValueWeakChar, kv,OBJC_ASSOCIATION_RETAIN);
//    }
//    return kv;
}

-(NSMutableDictionary<NSString*,id>*)keyValue
{

    NSMutableDictionary<NSString*,id> *kv= (NSMutableDictionary<NSString*,id>*)objc_getAssociatedObject(self, &keyValueChar);
    if(kv==nil)
    {
        kv=[NSMutableDictionary<NSString*,id> new];
        objc_setAssociatedObject(self, &keyValueChar, kv,OBJC_ASSOCIATION_RETAIN);
    }
    return kv;
}

经过在强引用的Dictionary里,保存一个弱引用NSTableMap,来存档一些索要弱引用的目的,比如View或Controller等对象。

正当本人在思考上边的解法的时候:另三个非凡的导航栏Crash难点也油不过生了,而且在偏下三种状态都会Crash掉:

传说出自:

典故是这么的,为了处理内部存款和储蓄器释放的标题,寻常人的记挂,都以给指标的dealloc扩大日志输出。

于是,UIView、UIViewController和三个Sagit定义的基类S电视机iew、STController,任天由命就增加了那般一行代码:

-(void)dealloc{
    NSLog(@"UIView relase -> %@", [self class]);
}

接下来就因此输出的日志,观望该方法被实践与否,来承认对象是或不是符合规律被放出。

在各样强引用、弱引用、循环引用、先强后弱引用的坑里跳来跳去后,终于祭出了一揽子的杀招,来处理那么些题材:

-(id)key:(NSString *)key
{
    id value=[self.keyValue get:key];
    if(value==nil)
    {
        value=[self.keyValueWeak get:key];
    }
    return value;
}
-(UIView*)key:(NSString *)key valueWeak:(id)value
{
    [self.keyValueWeak set:key value:value];
    return self;
}
-(UIView*)key:(NSString *)key value:(id)value
{
    [self.keyValue set:key value:value];
    return self;
}
-(NSMapTable*)keyValueWeak
{
    NSMapTable *kv=[self.keyValue get:@"keyValueWeak"];
    if(kv==nil)
    {
        kv=[NSMapTable mapTableWithKeyOptions:NSMapTableWeakMemory valueOptions:NSMapTableWeakMemory];
        [self.keyValue set:@"keyValueWeak" value:kv];
    }
    return kv;
//    NSMapTable *kv= (NSMapTable*)objc_getAssociatedObject(self, &keyValueWeakChar);
//    if(kv==nil)
//    {
//        kv=[NSMapTable mapTableWithKeyOptions:NSMapTableWeakMemory valueOptions:NSMapTableWeakMemory];
//        objc_setAssociatedObject(self, &keyValueWeakChar, kv,OBJC_ASSOCIATION_RETAIN);
//    }
//    return kv;
}

-(NSMutableDictionary<NSString*,id>*)keyValue
{

    NSMutableDictionary<NSString*,id> *kv= (NSMutableDictionary<NSString*,id>*)objc_getAssociatedObject(self, &keyValueChar);
    if(kv==nil)
    {
        kv=[NSMutableDictionary<NSString*,id> new];
        objc_setAssociatedObject(self, &keyValueChar, kv,OBJC_ASSOCIATION_RETAIN);
    }
    return kv;
}

由此在强引用的Dictionary里,保存三个弱引用NSTableMap,来存档一些急需弱引用的对象,比如View或Controller等对象。

正当本身在构思上边包车型大巴解法的时候:另3个丰硕的领航栏Crash难点也应运而生了,而且在偏下三种景况都会Crash掉:

导航栏命案一:回退即Crash

 一初始是通过导航栏回退看日志输出,结果却动不动给笔者来以此:

澳门永利234555com 1

主要还怎么全局断点、僵使对象等措施都行不通,只好靠猜〜〜〜〜〜

拍卖那么些难题吗,辛亏,小编是把代码折半注释,最终稳定到:

澳门永利234555com 2

圈起来的代码,是为每一个UI,都增加四个属性,前三个UI和后贰个UI。

竭泽而渔也很不难,用弱引用存档就好了(这几个时候,强弱引用的标题一度被本身完美消除了):

// Name
- (UIView*)preView{
    return [self key:@"preView"];
}
- (UIView*)preView:(UIView*)view
{
    return [self key:@"preView" valueWeak:view];
}

- (UIView*)nextView{
    return [self key:@"nextView"];
}
- (UIView*)nextView:(UIView*)view
{
    return [self key:@"nextView" valueWeak:view];
}

导航栏命案一:回退即Crash

 一开头是透过导航栏回退看日志输出,结果却动不动给本人来以此:

澳门永利234555com 3

注重还怎么全局断点、僵使对象等格局都不算,只可以靠猜〜〜〜〜〜

拍卖这些题目吧,辛亏,笔者是把代码折半注释,最终稳定到:

澳门永利234555com 4

圈起来的代码,是为每一个UI,都扩展多少个特性,前一个UI和后2个UI。

化解也非常的粗略,用弱引用存档就好了(这几个时候,强弱引用的题材早已被本人完美化解了):

// Name
- (UIView*)preView{
    return [self key:@"preView"];
}
- (UIView*)preView:(UIView*)view
{
    return [self key:@"preView" valueWeak:view];
}

- (UIView*)nextView{
    return [self key:@"nextView"];
}
- (UIView*)nextView:(UIView*)view
{
    return [self key:@"nextView" valueWeak:view];
}

导航栏命案2:回退一遍即Crash

上3次是援引难点,那三次啊?我X,错误的提示,仍然和上海体育场面一律,贰个main含数里让您猜〜〜〜〜〜

澳门永利234555com 5

再者一级就屡见不鲜,二级就挂给您看〜〜〜真不要脸。

下一场,就是对准那种灵异事件,各类渡,发现全球都没现身自个儿这些难题〜〜〜〜那真神了去了。

下一场又起来注释代码,神奇的发现,在弹回后退时,假如把上多个场地栏给重新安装2回,即不晤面世Crash现象。

所以,笔者是那样思考导航栏难点的:

    1: 一个navigationCtroller只有一个navigationBar。
    2: 每一个viewController,都会复写前一个navigationBar。
    3: 所以,到下一层时,UINavigationBar指向最后一个Controller
    4: 当回退时,最后一个Controller被释放后,navigationBar没有被重绘的话,事件指向就会出问题。

接下来又起来出手保存当前情景,然后后退时还原状态这条路。

是因为后退是自定义事件,所以能够在事件里加代码还原,可是一旦是滑动再次来到吗?

千身万苦之后,找到:shouldPopItem,在那边能够做点事情:

@implementation UINavigationController (ST)

#pragma mark NavigationBar 的协议,这里触发
// fuck shouldPopItem 方法存在时,只会触发导航栏后退,界面视图却不后退。
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item  // same as push methods
{
    //重设上一个Controller的导航(不然在二次Push后再Pop会Crash)
    NSInteger count=self.viewControllers.count;
    if(count>0)//发现这里返回的viewControllers,已经是移掉了当前的Controller后剩下的。
    {
        UIViewController *preController=self.viewControllers[count-1];//获取上一个控制器
        if([preController needNavBar])
        {
            [preController reSetNav:self];
        }
    }

    return YES;
}
//返回到当前页面
- (void)navigationBar:(UINavigationBar *)navigationBar didPopItem:(UINavigationItem *)item
{
//    if(navigationBar!=nil && [navigationBar.lastSubView isKindOfClass:[UIButton class]])
//    {
//       // [navigationBar.lastSubView height:0];//取消自定义复盖的UIButton
//    }
    NSInteger count=self.viewControllers.count;
    if(count>0)
    {
        UIViewController *current=self.viewControllers[count-1];
        self.navigationBar.hidden=![current needNavBar];
//        if(!self.navigationBar.isHidden)
//        {
//            [current reSetNav:self];
//        }
        if(self.tabBarController!=nil)
        {
            self.tabBarController.tabBar.hidden=![current needTabBar];
        }
    }
}
-(void)dealloc
{
    NSLog(@"UINavigationController relase -> %@", [self class]);
}
@end

改完事后,发现一切又健康了,然后,又迎来了导航栏的第二波bug。

(PS:shouldPopItem
这一个主意,是第1个一流Bug坑)

导航栏命案2:回退三回即Crash

上三回是引用难点,那2次啊?我X,错误的唤起,还是和上海教室一律,多少个main含数里让你猜〜〜〜〜〜

澳门永利234555com 6

还要一级就屡见不鲜,二级就挂给你看〜〜〜真不要脸。

下一场,正是指向那种灵异事件,各样渡,发现全球都没出现自身那个难点〜〜〜〜这真神了去了。

下一场又伊始注释代码,神奇的发现,在弹回后退时,假如把上叁个景色栏给重新安装2次,即不会产出Crash现象。

从而,作者是那样思考导航栏难题的:

    1: 一个navigationCtroller只有一个navigationBar。
    2: 每一个viewController,都会复写前一个navigationBar。
    3: 所以,到下一层时,UINavigationBar指向最后一个Controller
    4: 当回退时,最后一个Controller被释放后,navigationBar没有被重绘的话,事件指向就会出问题。

下一场又起来入手保存当前气象,然后后退时还原状态那条路。

澳门永利234555com,是因为后退是自定义事件,所以能够在事件里加代码还原,然而借使是滑动重回吗?

千身万苦之后,找到:shouldPopItem,在此处能够做点事情:

@implementation UINavigationController (ST)

#pragma mark NavigationBar 的协议,这里触发
// fuck shouldPopItem 方法存在时,只会触发导航栏后退,界面视图却不后退。
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item  // same as push methods
{
    //重设上一个Controller的导航(不然在二次Push后再Pop会Crash)
    NSInteger count=self.viewControllers.count;
    if(count>0)//发现这里返回的viewControllers,已经是移掉了当前的Controller后剩下的。
    {
        UIViewController *preController=self.viewControllers[count-1];//获取上一个控制器
        if([preController needNavBar])
        {
            [preController reSetNav:self];
        }
    }

    return YES;
}
//返回到当前页面
- (void)navigationBar:(UINavigationBar *)navigationBar didPopItem:(UINavigationItem *)item
{
//    if(navigationBar!=nil && [navigationBar.lastSubView isKindOfClass:[UIButton class]])
//    {
//       // [navigationBar.lastSubView height:0];//取消自定义复盖的UIButton
//    }
    NSInteger count=self.viewControllers.count;
    if(count>0)
    {
        UIViewController *current=self.viewControllers[count-1];
        self.navigationBar.hidden=![current needNavBar];
//        if(!self.navigationBar.isHidden)
//        {
//            [current reSetNav:self];
//        }
        if(self.tabBarController!=nil)
        {
            self.tabBarController.tabBar.hidden=![current needTabBar];
        }
    }
}
-(void)dealloc
{
    NSLog(@"UINavigationController relase -> %@", [self class]);
}
@end

改完事后,发现整整又健康了,然后,又迎来了导航栏的第①波bug。

(PS:shouldPopItem
这么些主意,是首个超级Bug坑)

导航栏命案3:第一个页面存在自定义按钮,则Crash

以下这些界面,右上角多个小相机事件。

澳门永利234555com 7

因为消除难点2的代码中,并从未过来第三个页的导航栏,所以事故恐怕发生了。

下一场又构思,那私下认可的率先个页面状态怎么保存?

一向保存整个UIButtonBar也许全体NavigationBar,再过来,竟然极度!!!

几乎欲哭无泪,各样渡,仍无果,为何整个世界,都没那种难题呢?

难道满世界写代码都以内部存款和储蓄器不自由,所以木有这么些难题?

如此基础的难点,不是四海都会蒙受的么?

下一场到了邻座小伙的微处理器上,把那种神奇的传说,在他电脑上再次演示了一次!!!

果不其然照旧和自身电脑上的等同!!!

果然那难题依旧很普遍,为何呢,渡不出果呢?

不精通干什么,作为一名新手,他跑去把那段代码给注释了:

//fuck dealloc 方法存在时,会影响导航的后退事件Crash,以下两种情况:1:当前UI有自定义导航按钮时;2:Push两层再回退。
//-(void)dealloc
//{
////    if(self.gestureRecognizers.count>0)
////    {
////        if(self.gestureRecognizers!=nil)
////        {
////            for (NSInteger i=self.gestureRecognizers.count-1; i>=0; i--)
////            {
////                [self removeGestureRecognizer:self.gestureRecognizers[i]];
////            }
////        }
////    }
//    //[self.keyValueWeak removeAllObjects];
//  //  [self.keyValue removeAllObjects];
//
//    NSLog(@"UIView relase -> %@ name:%@", [self class],self.name);
//}

然后,一切平常了〜〜〜〜咦!!!!

是dealloc里的代码有题目引发的?

然后里面代码全注释掉了,难题也许有!!!

把dealloc整个注释掉,又健康了!!!

导航栏命案3:第贰个页面存在自定义按钮,则Crash

以下这几个界面,右上角三个小相机事件。

澳门永利234555com 8

因为消除难点2的代码中,并没有恢复第叁个页的导航栏,所以事故依然时有发生了。

接下来又沉思,那暗中认可的第三个页面状态怎么保存?

直白保存整个UIButtonBar或许全部NavigationBar,再苏醒,竟然十三分!!!

几乎欲哭无泪,各类渡,仍无果,为什么举世,都没那种题材吧?

难道全球写代码都是内部存款和储蓄器不自由,所以木有那么些题材?

如此基础的难题,不是四处都会碰到的么?

下一场到了邻座小伙的处理器上,把那种神奇的旧事,在他电脑上再次演示了叁次!!!

果不其然依然和本人电脑上的等同!!!

果不其然那标题只怕很宽泛,为何呢,渡不出果呢?

不了然为啥,作为一名新手,他跑去把那段代码给注释了:

//fuck dealloc 方法存在时,会影响导航的后退事件Crash,以下两种情况:1:当前UI有自定义导航按钮时;2:Push两层再回退。
//-(void)dealloc
//{
////    if(self.gestureRecognizers.count>0)
////    {
////        if(self.gestureRecognizers!=nil)
////        {
////            for (NSInteger i=self.gestureRecognizers.count-1; i>=0; i--)
////            {
////                [self removeGestureRecognizer:self.gestureRecognizers[i]];
////            }
////        }
////    }
//    //[self.keyValueWeak removeAllObjects];
//  //  [self.keyValue removeAllObjects];
//
//    NSLog(@"UIView relase -> %@ name:%@", [self class],self.name);
//}

接下来,一切符合规律了〜〜〜〜咦!!!!

是dealloc里的代码很是掀起的?

下一场里面代码全注释掉了,难题还是有!!!

把dealloc整个注释掉,又健康了!!!

实质:IOS的Bug,不可能扩充UIView的dealloc方法

到了此处,真相到底出来了,只要扩展了UIView的dealloc方法,导航栏就敢死给您看!!!

作者了个去,为了查内部存款和储蓄器释放,所以要写dealloc方法,但写了这一个办法,就引出来这么多神奇的灵异事件。 

无语啊,那是为了让我们决不管内存释放难题,故意设下的坑么。

IOS除了那几个Bug,还有特别shouldPopItem事件,只要这么些事件存在,默许return
YES,就只重临导航头,不会回到界面,也是个坑!!!

效能是如此的:

澳门永利234555com 9

实为:IOS的Bug,不可能扩张UIView的dealloc方法

到了此地,真相终于出来了,只要扩张了UIView的dealloc方法,导航栏就敢死给你看!!!

自身了个去,为了查内部存款和储蓄器释放,所以要写dealloc方法,但写了那个格局,就引出来这么多神奇的灵异事件。 

无语啊,那是为了让我们不用管内部存款和储蓄器释放难题,故意设下的坑么。

IOS除了这些Bug,还有非凡shouldPopItem事件,只要那一个事件存在,暗中同意return
YES,就只重返导航头,不会回去界面,也是个坑!!!

意义是这么的:

澳门永利234555com 10

总结:

正是人算不如天算,遭逢这种坑,也是全宇宙第三位了。

那里给大家提供3个坑队友的的新点子:

找个地点,对UIView增加3个dealloc空方法。

下一场就说那Bug很神奇,让她推推搡搡看看,包对方头大两尺三〜〜〜

本来内部存储器泄漏的题材,到此篇就截至的,可是还有一个随便的标题想消除:

仰望在block里,任性的写self,也不会导致内部存款和储蓄器汇漏难题。

又经过48钟头的血战,终于化解了。

同时又发现另四个IOS的坑,好啊,只可以把此文改成人中学,准备再来一篇下。

总结:

真是人算不如天算,境遇那种坑,也是全宇宙第②人了。

此地给大伙提供一个坑队友的的新措施:

找个地点,对UIView扩张三个dealloc空方法。

然后就说那Bug很神奇,让她帮忙看看,包对方头大两尺三〜〜〜

本来内部存款和储蓄器泄漏的难题,到此篇就得了的,不过还有一个任意的标题想缓解:

意在在block里,任性的写self,也不会招致内部存款和储蓄器汇漏难点。

又通过48小时的奋战,终于消除了。

并且又发现另1个IOS的坑,可以吗,只能把此文字改正成人中学,准备再来一篇下。