贯彻自由CentOS系统内部存款和储蓄器的Shell脚本分享,onPrimaryClipChanged调用四次浅析

By admin in 4858美高梅 on 2019年5月5日

率先遭遇那么些需假若就种种百度,不过开掘基本都是用js完成,而且包容性还乌烟瘴气。

1、系统对象的复制

不论是集结类对象,照旧非集结类对象,接收到copymutableCopy音信时,都遵守以下规则:

  • copy返回immutable目的;所以,假设对copy再次来到值使用mutable目的接口就可以crash;
  • mutableCopy返回mutable对象;

下图详细阐释了NSStringNSMutableStringNSArrayNSMutableArrayNSDictionaryNSMutableDictionary分级调用copymutableCopy方法后的结果:

4858美高梅 1

背景:想要在Android
上做2个复制查词的功用。实现格局即在Service中得到ClipboardManager
加多ClipChangedListener。如此一来,当手提式有线电话机的剪贴板内容爆发退换时即会调用OnPrimaryClipChangedListener中onPrimaryClipChanged方法。不过在此进程中相见了一个主题素材,尽管当剪贴板内容爆发变动时onPrimaryClipChanged方法会被调用三遍。此篇小说即在分析为啥onPrimaryClipChanged方法会被调用三回。

这几天开掘CentOS系统内部存款和储蓄器一贯涨,固然把apache和mysql关闭了,内存也不自由,能够运用以下脚本来释放内部存款和储蓄器:
 
剧本内容:

4858美高梅,而是在追寻和尝试的进度中,开掘只要求css代码也可以完全得以达成的,对急需复制内容的价签加上下边这几行代码就足以了。

一.一 非集结类对象的copy与mutableCopy

系统非群集类对象指的是NSStringNSNumber等等的对象。下边看一下非群集类NSString对象拷贝的例证:

第一先想到的便是:是还是不是自己对ClipboardManager多次加多了Listener?
如下代码管理ClipboardManager的开首化以及对ClipboardManager增添监听,只有ClipboardManager为null时才会实行括号内的代码,当试行过括号内的代码之后,if中的条件不会再也创造,显明能够得出结论,我们的Listener只增多了三遍。

 

-webkit-touch-callout: all;
-webkit-user-select: all;
-moz-user-select: all;
-ms-user-select: all;
user-select: all;

copy

NSString *string = @"origin";
NSString *stringCopy = [string copy];
NSMutableString *stringMCopy = [string mutableCopy];

NSLog(@"%p", string);
NSLog(@"%p", stringCopy);
NSLog(@"%p", stringMCopy);

2016-03-10 17:32:04.479 Homework[21715:2353641] 0x1000d0ea0
2016-03-10 17:32:04.481 Homework[21715:2353641] 0x1000d0ea0
2016-03-10 17:32:04.481 Homework[21715:2353641] 0x17006fe40

因此查阅内部存款和储蓄器,能够看来stringCopystring的地点是同等,进行了指针拷贝;而stringMCopy的地点和string不雷同,进行了内容拷贝。

4858美高梅 2

复制代码 代码如下:

贯彻自由CentOS系统内部存款和储蓄器的Shell脚本分享,onPrimaryClipChanged调用四次浅析。骨子里意思就是不限制用户对剧情的操作,不禁止使用系统暗中认可菜单,长按会显示系统自带的复制功效拓展复制。

mutableCopy

NSMutableString *string      = [NSMutableString stringWithString: @"origin"];
//copy
NSString *stringCopy         = [string copy];
NSMutableString *mStringCopy = [string copy];
NSMutableString *stringMCopy = [string mutableCopy];

NSLog(@"%p", string);
NSLog(@"%p", stringCopy);
NSLog(@"%p", mStringCopy);
NSLog(@"%p", stringMCopy);

2016-03-10 17:34:11.486 Homework[21728:2354359] 0x17426f800
2016-03-10 17:34:11.487 Homework[21728:2354359] 0x174230600
2016-03-10 17:34:11.487 Homework[21728:2354359] 0x1742306e0
2016-03-10 17:34:11.487 Homework[21728:2354359] 0x174267240

//change value
[mStringCopy appendString:@"mm"]; //crash
[string appendString:@" origion!"];
[stringMCopy appendString:@"!!"];

crash的来头正是copy回到的目标是immutable对象。

Paste_Image.png

    #! /bin/bash  
    # cache释放:  
    # To free pagecache:  
    sync  
    sync  
    #echo 1 > /proc/sys/vm/drop_caches  
    # To free dentries and inodes:  
    #echo 2 > /proc/sys/vm/drop_caches  
    # To free pagecache, dentries and inodes:  
    echo 3 > /proc/sys/vm/drop_caches 

正是那般简单

壹.二 集结类对象的copy与mutableCopy

集结类对象是指NSArrayNSDictionaryNSSet等等的靶子。上面看一下集合类NSArray目标使用copymutableCopy的3个事例:

在调治代码的时候,在调节台发现了魔幻的事体:笔者是用的模拟器是Genymotion,它有1个成效,正是当你在Computer的任何分界面复制内容时,模拟器中的剪贴板内容也会发生变动!正是在自家复制的时候开掘采取计算机举办复制的onPrimaryClipChanged方法只会被调用二回。这几个正是大家所预期的景观啊,可是当自个儿在此在手提式有线电话机中张开复制的时候,发掘onPrimaryClipChanged方法还是会被调用五回!

接纳系统crontab落成每一日活动运维:

copy

NSArray *array = @[@[@"a", @"b"], @[@"c", @"d"]];
NSArray *copyArray = [array copy];
NSMutableArray *mCopyArray = [array mutableCopy];

NSLog(@"%p", array);
NSLog(@"%p", copyArray);
NSLog(@"%p", mCopyArray);

2016-03-10 17:53:40.113 Homework[21775:2358227] 0x17403f040
2016-03-10 17:53:40.114 Homework[21775:2358227] 0x17403f040
2016-03-10 17:53:40.114 Homework[21775:2358227] 0x174247e60

能够见见copyArrayarray的地点是壹模同样的,而mCopyArrayarray的地址是见仁见智的。表明copy操作进行了指针拷贝,mutableCopy进展了剧情拷贝。但须求重申的是:此处的剧情拷贝,仅仅是拷贝array以此目的,array聚焦内部的因素还是是指针拷贝。那和上边的非集合immutable目的的正片照旧挺相似的,那么mutable目的的拷贝会不会接近呢?大家继续往下,

难道说是Android底层音讯分发的难点?(自个儿使用ClipboardManager
调用setPrimaryClip,onPrimaryClipChanged方法也会被调用两遍)比不上就看看源代码吧!

复制代码 代码如下:

mutableCopy

NSMutableArray *array = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil];
NSArray *copyArray = [array copy];
NSMutableArray *mCopyArray = [array mutableCopy];

NSLog(@"%p", array);
NSLog(@"%p", copyArray);
NSLog(@"%p", mCopyArray);

2016-03-10 17:54:39.114 Homework[21782:2358605] 0x170058e40
2016-03-10 17:54:39.115 Homework[21782:2358605] 0x170058ed0
2016-03-10 17:54:39.115 Homework[21782:2358605] 0x170058ea0

查看内部存款和储蓄器,如我们所料,copyArraymCopyArrayarray的内存地址都不平等,表达copyArraymCopyArray都对array举办了内容拷贝。

4858美高梅 3

crontab -e

二、自定义对象的复制

使用copymutableCopy复制对象的别本使用起来的确有益,那么大家自定义的类是或不是可调用copymutableCopy格局来复制别本呢?大家先定义二个Person类,代码如下:

@interface Person : NSObject
@property (nonatomic, assign) NSInteger age;
@property (nonatomic, copy) NSString *name;

@end

接下来尝试调用Personcopy形式来复制二个别本:

Person *person1 = [[Person alloc] init];//创建一个Person对象
person1.age = 20;
person1.name = @"张三";
Person *person2 = [person1 copy];//复制副本

运作程序,将会爆发崩溃,并出口以下错误音讯:

[Person copyWithZone:]: unrecognized selector sent to instance 0x608000030920

地点的晋升:Person找不到copyWithZone:办法。大家将复制别本的代码换到如下:

 Person *person2 = [person1 mutableCopy];//复制副本

双重运转程序,程序同样崩溃了,并出口去以下错误音讯:

[Person mutableCopyWithZone:]: unrecognized selector sent to instance 0x600000221120

地点的唤起:Person找不到mutableCopyWithZone:方法。

大家兴许会认为疑忌,程序只是调用了copymutableCopy方法,为什么会提示找不到copyWithZone:mutableCopyWithZone:主意吧?其实当程序调用对象的copy格局来复制自个儿时,底层要求调用copyWithZone:办法来产生实际的复制职业,copy归来实际上就是copyWithZone:情势的再次来到值;mutableCopymutableCopyWithZone:办法也是平等的道理。

这就是说如何做技术让自定义的目的进行copymutableCopy呢?须要做以下专门的工作:

1.让类实现NSCopying/NSMutableCopying协议。
2.让类实现copyWithZone:/mutableCopyWithZone:方法

故而让我们的Person类能够复制本人,大家供给让Person实现NSCopying商业事务;然后达成copyWithZone:方法:

@interface Person : NSObject<NSCopying>
@property (nonatomic, assign) NSInteger age;
@property (nonatomic, copy) NSString *name;

@end

#import "Person.h"

@implementation Person
- (id)copyWithZone:(NSZone *)zone {
    Person *person = [[[self class] allocWithZone:zone] init];
    person.age = self.age;
    person.name = self.name;
    return person;
}

@end

运作之后发掘我们贯彻了对象的复制:

4858美高梅 4

并且必要注意的是只要目的中有任何指针类型的实例变量,且只是轻巧的赋值操作:person.obj2 = self.obj2,其中obj2是另三个自定义类,假如大家修改obj2中的属性,我们会发觉复制后的person对象中obj2对象中的属性值也变了,因为对于这一个目的并不曾进展copy操作,那样的复制操作不是截然的复制,如若要落到实处完全的复制,须要将obj2相应的类也要贯彻copy,然后那样赋值:person.obj2 = [self.obj2 copy]。如果目的众多还是层级许多,完成起来照旧很麻烦的。借使须求落成完全复制一样还有另有一种方法,那便是归档:

Person *person2 = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:person1]];

这么我们就落到实处了自定义对象的复制,须要提出的是假若重写copyWithZone:艺术时,其父类已经得以达成NSCopying合计,因人而异写过了copyWithZone:主意,那么子类重写copyWithZone:艺术应先调用父类的copy办法复制从父类承继获得的分子变量,然后对子类中定义的积极分子变量进行赋值:

- (id)copyWithZone:(NSZone *)zone {
        id obj = [super copyWithZone:zone];
        //对子类定义的成员变量赋值
        ...
        return obj;
}

关于mutableCopy的贯彻与copy的达成类似,只是完成的是NSMutableCopying协议与mutableCopyWithZone:措施。对于自定义的目的,在笔者眼里并不曾什么可变不可变的概念,因而达成mutableCopy事实上是绝非什么样含义的,在此就不详细介绍了。

Paste_Image.png

输入以下内容:

三、定义属性的copy提示符

如下段代码,大家在概念属性的时候利用了copy指示符:

#import <Foundation/Foundation.h>
@interface Person : NSObject<NSCopying>
@property (nonatomic, copy) NSMutableString *name;
@end

应用如下代码来进展测试:

Person *person1 = [[Person alloc] init];//创建一个Person对象
person1.name = [NSMutableString stringWithString:@"苏小妖"];
[person1.name appendString:@"123"];

运转程序会崩溃,并且提醒以下音信:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to mutate immutable object with appendString:'

那段错误提醒差异意修改personname本性,那是因为程序定义name品质时利用了copy指令符,该提醒符置顶调用setName:办法时(通过点语法赋值时,实际上是调用对应的setter办法),程序实际上会接纳参数的别本对name实则变量复制。也正是说,setName:措施的代码如下:

- (void)setName:(NSMutableString *)name {
    _name = [name copy];
}

copy办法私下认可是复制该对象的不可变别本,即便先后流传的NSMutableString,但先后调用该参数的copy艺术赢得的是不可变别本。因而,程序赋给Person对象的name实例变量的值依旧是不足变字符串。
  注意:定义合成gettersetter方法时并未提供mutableCopy提醒符。因而固然定义实例变量时利用了可变类型,但假使使用copy指令符,实例变量实际获得的值总是不可变对象。


参考文章:
iOS之对象复制
iOS的深复制与浅复制

4858美高梅 5

复制代码 代码如下:

Paste_Image.png

    00 00 * * * /root/Cached.sh 

总的看剪贴板发生改造的轩然大波分发情势reportPrimaryClipChanged并不在ClipboardManager类中调用。

每一日0点释放3回内部存款和储蓄器,那一个时间足以依据自身要求修改设置
 
在运维./Cached.sh时要是提醒错误:Permission denied
权限的难题,能够运作:

值得疑心的一些是,在Android
手提式有线电话机或然模拟器中当剪贴板事件产生改变时,大概会时有发生四次剪贴板爆发变动的事件。

复制代码 代码如下:

只是大家该怎么消除它吗?
在onPrimaryClipChanged方法中打个Log吧,显示一下系统的年月,看看一次调用的岁月差。然后在次给ClipboardManager注册二个Listener,只是展现时间,大家比较一下那八个Log,试试能还是不可能验证我们的猜忌,于是作者的代码产生了那样:

chmod +x .Cached.sh

4858美高梅 6

其它还足以由此改造/etc/sysctl.conf的章程来达到机关释放缓存的目标。可是内部存款和储蓄器不够用,最佳依然去找找别的的案由,举例程序设置是或不是创造,是不是突发访问量相当的大,或然程序设计不创建造成内部存储器溢出等,终归操作系统自个儿设计会怀想各省点的主题材料,强制腾出cache的大大小小,恐怕只是把难点给暂且屏蔽了,不便宜推断难题的大街小巷。

Paste_Image.png

在模拟器中展开文本复制之后,Log如下:

4858美高梅 7

Paste_Image.png

简言之的解析一下,我们报了名了八个监听First Listener 以及 Second
Listener。系统发生第二个剪贴板发生转移的风浪时。多个Litener都吸收到了事件,并且大致同时的调用了onPrimaryClipChanged方法,所以八个Listener打字与印刷出的系统时间周边(在自家的模拟器中时间是同壹,那几个小时是取决于onStartCommand方法所耗费时间间有多少长度,具体缘由可看ClipboardManager类中的reportPrimaryClipChanged方法)
当发出第二个剪贴板爆发变动的轩然大波时,再三回打字与印刷系统时间。

因此能够推断出事先的估摸很有相当的大希望是科学的。即,当Android
手提式有线电话机/模拟器中的剪贴板内容会产生改造时,系统会发出五次剪贴板改换的事件。然则那一个结论是测算出的,是或不是真的的百分之百的正确性,还必要阅读Clipboard的源码。

我们当下驾驭了原委,就可以稳步的提交解决方案。我们能够定义1个变量存款和储蓄第二个发出改换时间的年月,当第一回调用的时候,相比上3回剪贴板改变时间,假诺小于一定的时刻距离,就可以感觉这一次的剪贴板事件是船到江心补漏迟的。结合用户的操作,作者壹旦调用时间差为200微秒

4858美高梅 8

Paste_Image.png

迄今停止,那个难题的辨析以及缓和就已经终止啦,由于投机照旧Android界的入门级选手,水平多有不足,即使小说有尾巴,还指望各位引导辅导。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 美高梅手机版4858 版权所有