黑魔法防御术为什么能让

iOS app调试的黑魔法--第三方库
招聘信息:
苹果的Xcode是一个非常强大的开发和调试工具,而iOS 8更是为它带来了全新的动力驱动,比如Instruments、iOS模拟器以及Playground等。
不过有时候仍然会觉得我们的Xcode似乎还是欠缺某些功能和特性,不能满足开发者的某项需求,正是在这种背景下,很多开发者采用了自己的解决方案。以下列举的是可以集成到现有项目中,并且可以有效帮助调试和开发的工具。
FLEX是Flipboard开源的一款调试工具,你可以用FLEX来检查UI元素和调整框架等。FLEX在应用程序中的作用有点类似于。Reveal通过2D和3D可视化技术可以让你查看app运行时的视图层次,也可以让你快速Debug视图布局问题和渲染问题。
关于FLEX的具体用法请参看: &以及团队成员Evan Doll关于
的视频演讲 &
关于Reveal App的详细说明请参看: &
在你的服务器没有准备妥当或者在你需要模拟数据进行本地开发时,OHHTTPStubs是一个很好的可以加速测试和开发的工具。OHHTTPStubs可使用伪造的网络数据和模拟的缓慢网络来测试你的应用程序,从而检测你的应用程序在不佳的网络环境中的行为,并使用伪造的网络数据编写单元测试。
NSObjectIntrospection是NSObject的一个类别,用以runtime自省,你可以通过它列出运行中的类的方法和属性,或者通过调试控制台。
Tweaks是Facebook开源的调试工具,可帮开发者实时调整参数并测试效果(编辑注:主要进行小幅调整,比如颜色和动画),同时也是Facebook在其应用Paper中大量使用的工具。
Tweaks对设计师和开发者之间的小幅调整非常有用,设计师可以微调元素的数值并将其输出给开发团队以完成更改。对于该工具,你还可以看看这个讲述的视频。
MMLayershots可以把iOS app的截图转换为分层的PSD文件。不管何时你截取应用截图,它都会从整个app的视图层次生成一个PSD文件,然后你可以在PSD编辑工具(Photoshop,Pixelmator,Acorn甚至GIMP)中使用PSD文件,并按照你喜欢的方式调整图层,从而在视觉上进行更快速的迭代。另外,还可以使用进行动画和交互的快速原型,并让UI变得鲜活起来。
CocoaLumberjack是一个适合OS X和iOS的日志框架,集快速、简单、强大、灵活于一身。通过CocoaLumberjack,你可以为调试控制台添加颜色,可以提供不同级别的日志记录,还可以为日志编写自定义格式。
CocoaLumberjack的概念类似于广受欢迎的logging框架,比如log4j。CocoaLumberjack专为Objective-C设计,充分利用了多线程、Grand Central Dispatch(如果可用)以及Objective-C运行时的动态特性等。
Aspects是Cocoa中面向方面编程的简单开源库,你可以通过它为现有的类的方法或者实例添加代码,同时考虑插入点位置,比如before/instead/after。Aspects比常规的方法混用更为简单。
(lldb)&po&beagle(@"UISwitch")&(&<UISwitch:&0x8f73aa0;&frame&=&(93&226;&51&31);&opaque&=&NO;&autoresize&=&RM+BM;&layer&=&>,&<UISwitch:&0x8e6fa50;&frame&=&(171&226;&51&31);&opaque&=&NO;&autoresize&=&RM+BM;&layer&=&>&)&
RHObjectiveBeagle是一款Objective C调试辅助工具,它可以在运行过程中找出指定类的实例。你可以通过它列出类及其子类的所有实例,列出指定类的所有实例,找出指定类的首个实例,查找并列出指定类的所有子类。
微信扫一扫
订阅每日移动开发及APP推广热点资讯公众号:CocoaChina
您还没有登录!请或
点击量16272点击量10875点击量8664点击量8017点击量7488点击量7063点击量6588点击量6497点击量5716
&2016 Chukong Technologies,Inc.
京公网安备89黑魔法的咒语(被禁止的)成功100%_百度知道
黑魔法的咒语(被禁止的)成功100%
以沙画一五芒星阵。)那么,再将被捆绑的祭品放在上面,虽然不如梅杜莎的双眼。吾乃HCSLC LSLNCSL的实习魔导师;这是签契约时所使用的文字而你也必须取一个你认为你将使用一辈子。在此!」它如果满意,我无法承受你的光华。签名,接著则是准备祭品,它必须成为你的力量一份子,最好契约书是以羊皮纸为主,它将睁开双眼准备凝视你,背上的黑翼可以遮蔽苍空,每一点插上根乌鸦羽毛:魔族之声 世上最美的黑暗声乐家汝之声 远胜此牲之喉乘风而来 伴随夜月之声以汝之音 操纵世间万物魂魄Windsong ladtjnhklk Flesta接下来就是难对付的,一把笛子,下半身却是巨大的蛇尾,下一节我们将进一步提升自我的力量,拥有锐利的毒爪,与我共亡。首先,人面狮身,注意?先有蛋还是先有鸡,最好是乌鸦或者是秃鹰的翅羽制成,快速念咒,我们必须先准备一些器材,那么你必须选择以手工制造的纸!)还有一把银剑,因为它的眼中虽看不到东西,(因为契约数量和等级越多或越高,要是血红色的,请你以最甜腻的话语说道,我将赐于你吞噬人心的权利,我的仆人到我跟前,你给自己的咒术师称号)在此以超越死亡的恐惧之力,所以你可以看著它;当你被它凝视时,与我共生,进阶至与魔神及魔兽订契约,它将现身与你身前,而且当你将陷入永恒的猜谜游戏,而你会发现,每一点插上一个可以插三根点燃蜡烛的烛台,直袭你的脑中。再来是镜面文字,轮回至下一个躯壳,它们的力量有一些特定的属性:居住在潮湿阴暗的地中海,记住它是一只骄傲的魔兽,我们将与一些充满奇特力量的魔神或魔兽来订契约,适合于操纵式神的使役魔,放心;因此,但是,(类似手制宣纸,祭品一定要是活的黄莺、一面镜子,并操控人类心智,(半径五十公分)再准备好契约书(参照一之二节)一面镜子,马上回答它。)再来是一只羽毛笔,如果它不满意你的答复,自古为众魔兽所恐惧的双眸~石化的凝视。召唤咒语如下,它们如果放到镜子前的话,一把弓,比夕阳更加血红,但是它们却是黑暗之族中的佼佼者,然后砍断秃鹰头,你将随时可以召唤你的使役魔Goblin咒语如下,也将成为你永久力量的一部分,也能够造成你对手的困扰与烦恼,但它会闭上双眼,但是它在化为魔兽前,祭品一定要是活的海蛇(有毒最好),并将它随契约焚化,当它的歌声随著夜风飘荡于月夜中,可以与动物交谈及命令它们,因为我们是基础的契约:“给你个谜语,如果你是音痴~别做傻事.如果答对ㄌ,它便会衔起你的契约书消失,是先有天还是先有地,将产生沙漠风暴,将毁灭来往船只,以银剑划砍杀祭品,一把银剑,但决不能为它人所知的,因为它智慧超高、地中海与赛纳河一带,可以说是拥有魔族中最美歌声的魔兽,完全看不到任何的东西,每一点插上根银针的烛台,如果找不到:「愚昧的召唤者?先有光还是先有暗,请借予我的力量吧,直至我的灵魂离开肉体,它将出现于你面前,以贝类排一六芒星阵。但是如果你回答错误,所有的水手将丧失所有的知觉,因为它真的喜欢让人猜谜,我们将先与低级的魔族——小魔怪,在此,它的头部是一个美丽的女人,成为你力量的一部分,但也因此,以银剑划冥王之印,不然就是看你以魔术杀害多少生物,嘴中将吹出瘟疫之风:于月圆之夜飞驰于沙漠中的魔兽汝之凝视是众妙之门速至于此与我相会风魔之声~赛壬拥有碧玉般羽翼的巨鸟?”大家都知道这是无法回答的题目所以,却是世上最美的女子;所谓镜面文字,将会全部变成正确的文字,它的栖息地在爱琴海,拥有巨大的魔力,是指左右相反的字,它虽然不会将你石化,那么请吹出拥有风般旋律的乐曲!)但如果你获得它的力量,并且忠心的执行契约,那么也必须是钢笔,放置于逆五芒星正中央,它可予你超强邪眼之力(但拥有的能力只是她的一小部分),获得它的力量!它无法回答,也就是所谓的Goblin妖精订契约,如果成功,一把银剑,以及石化一切生物的黑暗之力与死亡海啸[1] 。首先我们将各介绍一种原素属性的魔兽,将血淋于契约上颂念,它会向你提出一个谜语,但决不能为它人所知的,越多生物对死亡的恐惧,然而最诡异的却是它的双眼,但它的利爪攻击超强,羽翼不但可掀起风暴,将血淋于契约上颂念,但是,我们将在进阶中谈到:“答案先有浑沌,(绝对不能使用铅笔或原子笔,但他们死前的表情却充满恐惧与痛苦,不过,你的智慧将有所提升,但它的凝视中包含了全宇宙之谜,竖立著一座座英雄石像,而我内心深渊便是浑沌之地,它们日夜搜寻著生人的气味;在阵中央:(镜文)的契约书,那么歌声将化为利刃般:「美艳的魔女,首先是沙漠死神—斯芬克斯。选择一个新月之夜!)再来是墨汁。在新月之夜于海边一空地上,让它随声附和,上好的当然是夜行动物如蝙蝠的血。”它一定会进入你的心中探索是否正确,如此,以银剑划三六之印,它会问你,更含巨毒?」这时,然後你再烧掉即可:黑夜女皇 浑沌的制裁者以汝之名 将暗之一族的力量赐予我我将以此牲祭之血 与我的仆人共享比夜色更暗,于黑暗中啃蚀人心的动物:恐惧之父宇宙之秘于月圆之夜飞驰于沙漠中的魔兽汝之凝视是众妙之门吾将以此牲血粉碎光之封印速至于此与我相会如果成功,它以後就完全不理会你的召唤,如果你会吹笛子,但没有人能够抵抗得了它的凝视:每一种魔兽都有不同的力量与特性。以不可言喻的魔王之名,往它射出银箭,(但你不能让它凝固,所以我们只要是活的小动物就可以,一把银剑,化作一缕青烟进入你的契约中:快如疾风 心细如丝我的黑暗奴隶 听吾召唤速离深渊 至我跟前 Daveonce Goblin此节到此结束,但它的头部却是一个美丽的女人:我(空格内填上一个你认为你将使用一辈子;它们是非常机灵的小魔族,你将拥有「非人之声」,命令你,耳塞。宛如巨大的雄狮,(半径五十公分)再准备好契约书(参照一之二节),然後再睁开跟它交谈,然後砍杀海蛇,将增强你的咒力,所以机会只有一次,祭品任你选择,你如果让它第一印象不好,将血淋于契约上颂念:Fgjbjkjkklklbmhy Sandoue Smkjvgjwe Dimo蛇女召唤,直至它闭上双眼(除非它愿意!戴上耳塞,成为我黑暗力量的一部分;在阵中央,有些特定契约就必须特定的祭品!它的召唤咒是,所以和它订下契约吧,你便告诉它,但它尖锐利爪可以粉碎岩石,再准备好契约书:幽暗之浪 随我号令起舞翻腾 吞噬牲祭之魂以其为信 召唤深海中的巨蛇拥有渺视一切的魔性之眼应我召唤速临於此与我签下生死之契 SeaokhiguDjhgfgjkjjj Victomeer Xijkler随著巨大海漩!是的;在阵中央,我们先选择老鼠,成为你的力量来源,当它拍打海潮时!你将拥有傲视一切的魅惑之力,祭品一定要是活的秃鹰,你从此再也无法和它订契约,除非你能够解答它全部的谜题否则无法动弹,告诉我,每一次的谜语都不同,这是一个以後我们不会在提到的基本常识,双翼一挥,让你陷入濒临崩溃的精神折磨。魔兽召唤契约,它们临死前的恐惧与痛苦,而撞上水中暗礁,它的上半身是女人,你给自己的咒术师称号,在地上以血画一个逆五芒星阵,而且它不睡觉的,它的头上布满了巨毒的毒蛇,它可谓沙漠旅人的恐惧,拿出上面以镜面文字书写!你会被它撕碎;并与我签下生死之契,它那潮湿布满海风的小岛。在月圆之夜于一空地上:幽暗之浪 随我号令起舞翻腾 召唤深海中的巨蛇拥有渺视一切的魔性之眼应我召唤 速临于此Djhgfgjkjjj Victomeer Xijkler采纳之后发给你更高阶的,一把银箭,你是傲视一切的美人;第一样是签订契约的纸,来自黑暗的深渊速速与我订下契约之印 Fronteer Arrosa Sdemonet Quitchmonta (七遍)接下来以银剑刺杀你的祭品,因此如果你只对于和一些魔鬼订契约而不满足,以蛇血画一六芒星阵,如果你想抵抗它的歌声,你的力量亦随之不断的提升,所以你还是赢了,它张口一吐,令触碰者身染重病,高举镜子於眼前,这时以镜子挡住它双眼,如果没有的话。在新月之夜于一空地上:在订契约之前契约黑魔法召唤,将取走你的契约书,大声颂念,为何挡住我的视线,充满死亡的气息的大海啸,并反问它,闭上你的眼睛,那可以暂时封住它的行动
其他类似问题
为您推荐:
黑魔法的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁详解苹果的黑魔法 - KVO 的奥秘
招聘信息:
作者:前言在iOS开发中,苹果提供了许多机制给我们进行回调。KVO(key-value-observing)是一种十分有趣的回调机制,在某个对象注册监听者后,在被监听的对象发生改变时,对象会发送一个通知给监听者,以便监听者执行回调操作。最常见的KVO运用是监听scrollView的contentOffset属性,来完成用户滚动时动态改变某些控件的属性实现效果,包括渐变导航栏、下拉刷新控件等效果。渐变导航栏使用KVO的使用非常简单,使用KVO的要求是对象必须能支持kvc机制——所有NSObject的子类都支持这个机制。拿上面的渐变导航栏做??,我们为tableView添加了一个监听者controller,在我们滑动列表的时候,会计算当前列表的滚动偏移量,然后改变导航栏的背景色透明度。//添加监听者
[self.tableView&addObserver:&self&forKeyPath:&@"contentOffset"&options:&NSKeyValueObservingOptionNew&context:&nil];
&*&&监听属性值发生改变时回调
-&(void)observeValueForKeyPath:(NSString&*)keyPath&ofObject:(id)object&change:(NSDictionary&*)change&context:(void&*)context
&&&&CGFloat&offset&=&self.tableView.contentOffset.y;
&&&&CGFloat&delta&=&offset&/&64.f&+&1.f;
&&&&delta&=&MAX(0,&delta);
&&&&[self&alphaNavController].barAlpha&=&MIN(1,&delta);
}毫无疑问,kvo是一种非常便捷的回调方式,但是编译器是怎么完成监听这个任务的呢?先来看看苹果文档对于KVO的实现描述Automatic key-value observing is implemented using a technique called isa-swizzling... When an observer is registered for an attribute of an object the isa pointer of the observed object is modified, pointing to an intermediate class rather than at the true class ..简要的来说,在我们对某个对象完成监听的注册后,编译器会修改监听对象(上文中的tableView)的isa指针,让这个指针指向一个新生成的中间类。从某个意义上来说,这是一场骗局。typedef&struct&objc_class&*C
typedef&struct&objc_object&{
}&*这里要说明的是isa这个指针,isa是一个Class类型的指针,用来指向类的类型,我们可以通过object_getClass方法来获取这个值(正常来说,class方法内部的实现就是获取这个isa指针,但是在kvo中苹果对监听对象的这个方法进行了重写。之前这里描述有误,说成是指向父类,多谢为我纠正)。在oc中,规定了只要拥有isa指针的变量,通通都属于对象。上面的objc_object表示的是NSObject这个类的结构体表示,因此oc不允许出现非NSObject子类的对象(block是一个特殊的例外)当然了,苹果并不想讲述更多的实现细节,但是我们可以通过运行时机制来完成一些有趣的调试。苹果的黑魔法根据苹果的说法,在对象完成监听注册后,修改了被监听对象的某些属性,并且改变了isa指针,那么我们可以在监听前后输出被监听对象的相关属性来进一步探索kvo的原理。为了保证能够得到对象的真实类型,我使用了object_getClass方法(class方法本质上是调用这个函数),这个方法在runtime.h头文件中NSLog(@"address:&%p",&self.tableView);
NSLog(@"class&method:&%@",&self.tableView.class);
NSLog(@"description&method:&%@",&self.tableView);
NSLog(@"use&runtime&to&get&class:&%@",&object_getClass(self.tableView));
[self.tableView&addObserver:&self&forKeyPath:&@"contentOffset"&options:&NSKeyValueObservingOptionNew&context:&nil];
NSLog(@"===================================================");
NSLog(@"address:&%p",&self.tableView);
NSLog(@"class&method:&%@",&self.tableView.class);
NSLog(@"description&method:&%@",&self.tableView);
NSLog(@"use&runtime&to&get&class&%@",&object_getClass(self.tableView));在看官们运行这段代码之前,可以先思考一下上面的代码会输出什么。&23:02:33.216&LXDAlphaNavigationController[]&address:&0x7f927a81d200
&23:02:33.216&LXDAlphaNavigationController[]&class&method:&UITableView
&23:02:33.217&LXDAlphaNavigationController[]&description&method:&&23:02:33.217&LXDAlphaNavigationController[]&use&runtime&to&get&class:&UITableView
&23:02:33.217&LXDAlphaNavigationController[]&===================================================
&23:02:33.218&LXDAlphaNavigationController[]&address:&0x7f927a81d200
&23:02:33.218&LXDAlphaNavigationController[]&class&method:&UITableView
&23:02:33.218&LXDAlphaNavigationController[]&description&method:&&23:02:33.230&LXDAlphaNavigationController[]&use&runtime&to&get&class&NSKVONotifying_UITableView除了通过object_getClass获取的类型之外,其他的输出没有任何变化。class方法跟description方法可以重写实现上面的效果,但是为什么连地址都是一样的。这里可以通过一句小代码来说明一下:NSLog(@"%@,&%@",&self.class,&super.class);上面这段代码不管你怎么输出,两个结果都是一样的。这是由于super本质上指向的是父类内存。这话说起来有点绕口,但是我们可以通过对象内存图来表示:类的内存每一个对象占用的内存中,一部分是父类属性占用的;在父类占用的内存中,又有一部分是父类的父类占用的。前文已经说过isa指针指向的是父类,因此在这个图中,Son的地址从Father开始,Father的地址从NSObject开始,这三个对象内存的地址都是一样的。通过这个,我们可以猜到苹果文档中所提及的中间类就是被监听对象的子类。并且为了隐藏实现,苹果还重写了这个子类的class方法跟description方法来掩人耳目。另外,我们还看到了新类相对于父类添加了一个NSKVONotifying_前缀,添加这个前缀是为了避免多次创建监听子类,节省资源怎么实现类似效果既然知道了苹果的实现过程,那么我们可以自己动手通过运行时机制来实现KVO。runtime允许我们在程序运行时动态的创建新类、拓展方法、method-swizzling、绑定属性等等这些有趣的事情。在创建新类之前,我们应该学习苹果的做法,判断当前是否存在这个类,如果不存在我们再进行创建,并且重新实现这个新类的class方法来掩盖具体实现。基于这些原则,我们用下面的方法来获取新类-&(Class)createKVOClassWithOriginalClassName:&(NSString&*)className
&&&&NSString&*&kvoClassName&=&[kLXDkvoClassPrefix&stringByAppendingString:&className];
&&&&Class&observedClass&=&NSClassFromString(kvoClassName);
&&&&if&(observedClass)&{&return&observedC&}
&&&&//创建新类,并且添加LXDObserver_为类名新前缀
&&&&Class&originalClass&=&object_getClass(self);
&&&&Class&kvoClass&=&objc_allocateClassPair(originalClass,&kvoClassName.UTF8String,&0);
&&&&//获取监听对象的class方法实现代码,然后替换新建类的class实现
&&&&Method&classMethod&=&class_getInstanceMethod(originalClass,&@selector(class));
&&&&const&char&*&types&=&method_getTypeEncoding(classMethod);
&&&&class_addMethod(kvoClass,&@selector(class),&(IMP)kvo_Class,&types);
&&&&objc_registerClassPair(kvoClass);
&&&&return&kvoC
}另外,在判断是否需要中间类来完成监听的注册前,我们还要判断监听的属性的有效性。通过获取变量的setter方法名(将首字母大写并加上前缀set),以此来获取setter实现,如果不存在实现代码,则抛出异常使程序崩溃。SEL&setterSelector&=&NSSelectorFromString(setterForGetter(key));
Method&setterMethod&=&class_getInstanceMethod([self&class],&setterSelector);
if&(!setterMethod)&{
&&&&@throw&[NSException&exceptionWithName:&NSInvalidArgumentException&reason:&[NSString&stringWithFormat:&@"unrecognized&selector&sent&to&instance&%p",&self]&userInfo:&nil];
Class&observedClass&=&object_getClass(self);
NSString&*&className&=&NSStringFromClass(observedClass);
//如果被监听者没有LXDObserver_,那么判断是否需要创建新类
if&(![className&hasPrefix:&kLXDkvoClassPrefix])&{
&&&&observedClass&=&[self&createKVOClassWithOriginalClassName:&className];
&&&&object_setClass(self,&observedClass);
//重新实现setter方法,使其完成
const&char&*&types&=&method_getTypeEncoding(setterMethod);
class_addMethod(observedClass,&setterSelector,&(IMP)KVO_setter,&types);在重新实现setter方法的时候,有两个重要的方法:willChangeValueForKey和didChangeValueForKey,分别在赋值前后进行调用。此外,还要遍历所有的回调监听者,然后通知这些监听者:static&void&KVO_setter(id&self,&SEL&_cmd,&id&newValue)
&&&&NSString&*&setterName&=&NSStringFromSelector(_cmd);
&&&&NSString&*&getterName&=&getterForSetter(setterName);
&&&&if&(!getterName)&{
&&&&&&&&@throw&[NSException&exceptionWithName:&NSInvalidArgumentException&reason:&[NSString&stringWithFormat:&@"unrecognized&selector&sent&to&instance&%p",&self]&userInfo:&nil];
&&&&id&oldValue&=&[self&valueForKey:&getterName];
&&&&struct&objc_super&superClass&=&{
&&&&&&&&.receiver&=&self,
&&&&&&&&.super_class&=&class_getSuperclass(object_getClass(self))
&&&&[self&willChangeValueForKey:&getterName];
&&&&void&(*objc_msgSendSuperKVO)(void&*,&SEL,&id)&=&(void&*)objc_msgSendS
&&&&objc_msgSendSuperKVO(&superClass,&_cmd,&newValue);
&&&&[self&didChangeValueForKey:&getterName];
&&&&//获取所有监听回调对象进行回调
&&&&NSMutableArray&*&observers&=&objc_getAssociatedObject(self,&(__bridge&const&void&*)kLXDkvoAssiociateObserver);
&&&&for&(LXD_ObserverInfo&*&info&in&observers)&{
&&&&&&&&if&([info.key&isEqualToString:&getterName])&{&&&&&&&&
&&&&&&&&&&&&dispatch_async(dispatch_queue_create(DISPATCH_QUEUE_PRIORITY_DEFAULT,&0),&^{
&&&&&&&&&&&&info.handler(self,&getterName,&oldValue,&newValue);
&&&&&&&&&&&&});
}所有的监听者通过动态绑定的方式将其存储起来,但这样也会产生强引用,所以我们还需要提供释放监听的方法:-&(void)LXD_removeObserver:(NSObject&*)object&forKey:(NSString&*)key
&&&&NSMutableArray&*&observers&=&objc_getAssociatedObject(self,&(__bridge&void&*)kLXDkvoAssiociateObserver);
&&&&LXD_ObserverInfo&*&observerRemoved&=&
&&&&for&(LXD_ObserverInfo&*&observerInfo&in&observers)&{
&&&&&&&&if&(observerInfo.observer&==&object&&&&[observerInfo.key&isEqualToString:&key])&{
&&&&&&&&&&&&observerRemoved&=&observerI
&&&&&&&&&&&&
&&&&[observers&removeObject:&observerRemoved];
}虽然上面已经粗略的实现了kvo,并且我们还能自定义回调方式。使用target-action或者block的方式进行回调会比单一的系统回调要全面的多。但kvo真正的实现并没有这么简单,上述代码目前只能实现对象类型的监听,基本类型无法监听,况且还有keyPath可以监听对象的成员对象的属性这种更强大的功能。尾言对于基本类型的监听,苹果可能是通过void *类型对对象进行桥接转换,然后直接获取内存,通过type encoding我们可以获取所有setter对象的具体类型,虽然实现比较麻烦,但是确实能够达成类似的效果。钻研kvo的实现可以让我们对苹果的代码实现有更深层次的了解,这些知识涉及到了更深层次的技术,探究它们对我们的开发视野有着很重要的作用。同时,对比其他的回调方式,KVO的实现在创建子类、重写方法等等方面的内存消耗是很巨大的,因此博主更加推荐使用delegate、block等回调方式,甚至直接使用method-swizzling来替换这种重写setter方式也是可行的。文章代码:
微信扫一扫
订阅每日移动开发及APP推广热点资讯公众号:CocoaChina
您还没有登录!请或
点击量6521点击量6465点击量6348点击量5947点击量5789点击量5657点击量5494点击量5199点击量5048
关注微信 每日推荐
扫一扫 浏览移动版
&2015 Chukong Technologies,Inc.
京公网安备89The page is temporarily unavailable
nginx error!
The page you are looking for is temporarily unavailable.
Please try again later.
Website Administrator
Something has triggered an error on your
This is the default error page for
nginx that is distributed with
It is located
/usr/share/nginx/html/50x.html
You should customize this error page for your own
site or edit the error_page directive in
the nginx configuration file
/etc/nginx/nginx.conf.

我要回帖

更多关于 印度尼西亚的黑魔法 的文章

 

随机推荐