技术了解以及渗透
2017-02-09 10:42
344 查看
1,写一个标注的宏MIN,这个宏输入两个参数并返回最小的一个。
#defineMIN(A,B)((A)<(B)?(A):(B))
2,重写setter方法用于完成@property(nonatommic,retain)Object*obj;
-(void)setObj:(Class*)objValue{
if(obj!=objValue){
[objrelease];
obj=[valueretain];
}
}
3.assign,retain,copy区别,以及ARC下的weak,strong;
assign:简单赋值,不更改索引计数
copy:建立一个索引计数为1的对象,然后释放旧对象
retain:释放旧的对象,将旧对象的值赋予输入对象,再提高输入对象的索引计数为1;
Copy其实是建立了一个相同的对象,而retain不是:
比如一个NSString对象,地址为0×1111,内容为@”STR”
Copy到另外一个NSString之后,地址为0×2222,内容相同,新的对象retain为1,旧有对象没有变化
retain到另外一个NSString之后,地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的retain值+1
也就是说,retain是指针拷贝,copy是内容拷贝。在拷贝之前,都会释放旧的对象。
*使用assign:
对基础数据类型(NSInteger)和C数据类型(int,float,double,char,等)
*使用copy:对NSString
*使用retain:对其他NSObject和其子类
ARC(Automatic
ReferenceCounting)。简单地说,就是代码中自动加入了retain/release,原先需要手动添加的用来处理内存管理的引用计数的代码可以自动地由编译器完成了。
苹果官网只是图
4.release,autorelease,autoreleasepool,ARC,是什么,他们的机制以及区别;
5.使用block或使用delegate完成委托有什么优缺点,重写和重载;
重载(overload):函数名相同,函数的参数列表不同(包括参数个数和参数类型),至于返回类型可同可不同。重载既可以发生在同一个类的不同函数之间,也可发生在父类子类的继承关系之间,其中发生在父类子类之间时要注意与重写区分开。
重写(override):发生于父类和子类之间,指的是子类不想继承使用父类的方法,通过重写同一个函数的实现实现对父类中同一个函数的覆盖,因此又叫函数覆盖。注意重写的函数必须和父类一模一样,包括函数名、参数个数和类型以及返回值,只是重写了函数的实现,这也是和重载区分开的关键。
首先要了解什么是委托模式,委托模式在iOS中大量应用,其在设计模式中是适配器模式中的对象适配器,Objective-C中使用id类型指向一切对象,使委托模式在iOS中的实现更为方便。了解委托模式的细节:
iOS设计模式----委托模式
使用block实现委托模式,其优点是回调的block代码块定义在委托对象函数内部,使代码更为紧凑;
1.有多个相关方法。假如每个方法都设置一个block,这样会更麻烦。而delegate让多个方法分成一组,只需要设置一次,就可以多次回调。当多于3个方法时就应该优先采用delegate。
比如一个网络类,假如只有成功和失败两种情况,每个方法可以设计成单独block。但假如存在多个方法,比如有成功、失败、缓存、https验证,网络进度等等,这种情况下,delegate就要比block要好。
2.为了避免循环引用,也可以使用
delegate。使用block时稍微不注意就形成循环引用,导致对象释放不了。这种循环引用,一旦出现就比较难检查出来。而delegate的方法是分离开的,并不会引用上下文,因此会更安全些。
6.NSArray,NSMutableArray的区别,Copy,MutableCopy的区别,
copy与retain的区别:copy是创建一个新对象,retain是创建一个指针,引用对象计数加1。Copy属性表示两个对象内容相同,新的对象retain为1,与旧有对象的引用计数无关,旧有对象没有变化。copy减少对象对上下文的依赖。
对于系统的非容器类对象,对一不可变对象复制,copy是指针复制(浅拷贝)和mutableCopy就是对象复制(深拷贝)。如果是对可变对象复制,都是深拷贝,但是copy返回的对象是不可变的。
对于系统的容器类对象,以上规则同样适用,但是容器内的元素全部都是浅拷贝,也就是说所有的元素拷贝的仅仅是指针,内存没被复制。
1.copy:不可变复制
2.mutableCopy:可变复制
对receiver的要求不一样
1.copy:receiver必须实现NSCopying协议
2.mutableCopy:receiver必须实现NSMutableCopying协议
执行效果不一样
1.如果receiver是不可变容器
1)copy:返回receiver,并且receiver的引用计数加1,等效于retain
2)mutableCopy:由receiver中的数据构造一个新的可变实例
2.如果receiver是可变容器
1)copy:由receiver中的数据构造一个新的不可变实例
2)mutableCopy:由receiver中的数据构造一个新的可变实例
3.原因
为什么SDK对不同类型的receiver会产生如此多种结果。主要考虑以下方面
1)达到定义要求的效果。(参考上面定义中的描述)
2)尽量节省资源开销。
基于这第2)点。所以当receiver是不可变容器的时候,接收到copy消息时。只要达到retain的效果就可以了。这样一方面可以满足定义的要求,另一主面可以节省资源。
4.特定应用
1)为什么property声明中只有“copy”特性而没有“mutableCopy”特性。这是由于当声明property为"copy"特性时,系统会自动根据receiver的特点决定使用copy(已含retain的情况)还是mutableCopy。
2)所以对于容器类的property特性一般使用“copy”而不使用“retain”,交由系统根据receiver自己决定以达到最好的效果。
NSArray可以看成是线程安全,NAMutablearray可变数组非线程安全
功能单一,实现起来会更简单。
没有修改的数据的接口,就从根源防止了数据无意中被修改。
因为不会被修改,更容易被缓存复用。
因为不可变,只读,多线程访问的时候,也不会发生一边读一边写的情况,也就没有同步的问题,也就不用上锁。
7,NSNotification和KVO的区别和用法是什么?什么时候应该使用通知,什么时候应该使用KVO,它们的实现上有什么区别吗?如果用protocol和delegate(或者delegate的Array)来实现类似的功能可能吗?如果可能,会有什么潜在的问题?如果不能,为什么?
NSNotification是通知模式在iOS的实现,KVO的全称是键值观察(Key-valueobserving),其是基于KVC(key-value
coding)的,KVC是一个通过属性名访问属性变量的机制。例如将Model层的变化,通知到多个Controller对象时,可以使用NSNotification;如果是只需要观察某个对象的某个属性,可以使用KVO。
对于委托模式,在设计模式中是对象适配器模式,其是delegate是指向某个对象的,这是一对一的关系,而在通知模式中,往往是一对多的关系。委托模式,从技术上可以现在改变delegate指向的对象,但不建议这样做,会让人迷惑,如果一个delegate对象不断改变,指向不同的对象。
7Runtime是什么!
RunTime简称运行时。就是系统在运行的时候的一些机制,其中最主要的是消息机制。对于C语言,函数的调用在编译的时候会决定调用哪个函数(C语言的函数调用请看这里)。编译完成之后直接顺序执行,无任何二义性。OC的函数调用成为消息发送。属于动态调用过程。在编译的时候并不能决定真正调用哪个函数(事实证明,在编
译阶段,OC可以调用任何函数,即使这个函数并未实现,只要申明过就不会报错。而C语言在编译阶段就会报错)。只有在真正运行的时候才会根据函数的名称找到对应的函数来调用。
Objective-C语言将许多决策可以在编译时和运行时链接的时间。只要有可能,它的东西动态。这意味着,语言需要的不仅仅是一个编译器,而且运行时系统执行编译后的代码。运行时系统作为一种用于Objective-C语言的操作系统;它使语言文字工作。
这个文件看
All
Forthemostpart,theruntimesystemworksautomaticallyandbehindthescenes.YouuseitjustbywritingandcompilingObjective-Csourcecode.
当你编译包含Objective-C类和方法的代码,编译器创建的数据结构和函数,实现语言的动态特性要求。数据结构捕捉类别定义和协议声明发现信息;包括讨论中的类和协议的对象定义一个类和协议进入Objective-C编程语言,以及方法的选择,实例变量的模板,和其他信息从源代码中提取。主要的运行时功能是发送消息,如发送消息。这是援引消息源代码中的表达。
运行时系统是一个动态共享库的一个公共接口由一组函数和数据位于目录的头文件的结构Objective-C运行时参考
1.1Theobjc_msgSendFunction
InObjective-C,messagesaren’t
boundtomethodimplementationsuntilruntime.Thecompilerconvertsamessageexpression
[receivermessage]
接收到类名的调用后可以转化为消息底层的发送机制,或多参数的发送
消息传递函数为动态绑定做所有必要的工作:
Itfirstfindstheprocedure(methodimplementation)thattheselectorrefersto.Sincethesamemethodcanbeimplementeddifferently
byseparateclasses,thepreciseprocedurethatitfindsdependsontheclassofthereceiver.
Itthencallstheprocedure,passingitthereceivingobject(apointertoitsdata),alongwithanyargumentsthatwerespecifiedforthemethod.
Finally,itpassesonthereturnvalueoftheprocedureasitsownreturnvalue.
消息传递的关键在于编译器为每个类和对象构建的结构。每个阶级结构包括这两个基本要素:
Apointertothesuperclass.
Aclassdispatchtable.Thistablehasentriesthatassociatemethod
selectorswiththeclass-specificaddressesofthemethodstheyidentify.Theselectorforthe
thatimplements)
isassociatedwith
Figure
3-1MessagingFramework
Whenamessageissenttoanobject,themessagingfunctionfollowstheobject’s
totheclassstructurewhereitlooksupthemethodselectorinthedispatchtable.Ifitcan’tfindtheselectorthere,
thesuperclassandtriestofindtheselectorinitsdispatchtable.Successivefailurescause
Onceitlocatestheselector,thefunctioncallsthemethodenteredinthetableandpassesitthereceivingobject’sdatastructure.
Thisisthewaythatmethodimplementationsarechosenatruntime—or,inthejargonofobject-orientedprogramming,thatmethodsaredynamicallyboundtomessages.
加速消息传递过程中,运行时系统缓存使用选择器和地址的方法。有一个单独的缓存中为每个类,它可以包含继承的方法以及方法的选择器中定义的类。之前搜索调度表,收到的消息传递程序首先检查缓存对象的类(在理论,一种方法是使用一次可能会再次使用)。如果选择器的方法是在缓存中,消息传递是仅略低于一个函数调用。一旦一个程序被运行足够长的时间来“热身”其缓存,几乎所有它发送的消息找到缓存的方法。缓存生长在程序运行时动态地适应新的消息。
When
theprocedurethatimplementsamethod,itcallstheprocedureandpassesitalltheargumentsinthemessage.Italsopassestheproceduretwohiddenarguments:
Thereceivingobject
Theselectorforthemethod
为了规避动态绑定的唯一方法是得到方法的地址仿佛它是一个函数调用,它直接。这可能是适当的在罕见的情况下,当一个特定的方法将陆续进行了很多次,你想避免消息每次执行方法的开销。
一个定义的方法
下面的例子显示了如何的程序实现
第一个参数传递给程序接收的对象(
使用
请注意,
Therearesituationswhereyoumightwanttoprovideanimplementationofamethoddynamically.Forexample,theObjective-Cdeclaredpropertiesfeature(seeDeclared
PropertiesinTheObjective-CProgrammingLanguage)includesthe
Youcanimplementthemethods
dynamicallyprovideanimplementationforagivenselectorforaninstanceandclassmethodrespectively.
AnObjective-CmethodissimplyaCfunctionthattakeatleasttwoarguments—
Youcanaddafunctiontoaclassasamethodusingthefunction
Therefore,giventhefollowingfunction:
youcandynamicallyaddittoaclassasamethod(called
this:
一个Objective-C程序可以加载和链接新课和类别而它的运行。新的代码加入到程序和处理相同的类和类开始加载。
动态加载可以用来做很多不同的事情。例如,在系统偏好设置中的各个模块的动态加载。
在可可的环境,动态加载通常用于允许应用程序定制。别人可以写你的程序在运行时加载多界面生成器加载自定义调色板和OSX系统偏好设置自定义模块加载应用程序的偏好。加载模块扩展您的应用程序可以做什么。它们有助于它的方式,你允许但不可预期的或定义自己。你提供的框架,但其他人提供的代码。
虽然是一个运行时函数的执行,在Objective-CMach-O文件动态加载模块(
X的ABIMach-O文件格式参考用于信息是Mach-O文件。
遇到一个方法调用时,编译器会生成一个调用的一个函数
Whenitencountersamethodcall,thecompilergeneratesacalltooneofthefunctions
or
aresentusing
Methodsthathavedatastructuresasreturnvaluesaresentusing
8ARC?
ARC的工作原理是编译时添加代码,以确保对象在必要的时候生存,并不是你记得的什么时候release,return和autorelease,ARC对你的对象的生存期的要求和自动插入适当的内存管理当你在编译的时候,编译器也会为你生成合适的dealloc方法,
Acompleteandcorrectimplementationofa
(Objectpropertiesare
isdescribedinARC
IntroducesNewLifetimeQualifiers.)
UsingARC,youcouldimplementacontrivedmethodlikethis:
ARCtakescareofmemorymanagementsothatneitherthe
areleaked.
Youcouldalsosafelyimplementa
this:
ARCensuresthat
ARC的一些新的规则:
工作时,arc对一些新的规章制度,不使用其他编译模式。该规则旨在提供一个完全可靠的内存管理模型;在某些情况下,他们只是执行的最佳实践,在一些可以简化代码或是明显的你不必处理内存管理的推论。如果你违反了这些规则,你会得到一个即时编译时错误,不是一个微妙的错误,可能会在运行时明显。
Youcannotexplicitlyinvoke
or
Theprohibitionextendstousing
andsoon.
Youmayimplementa
instancevariables.Youdonothaveto(indeedyoucannot)releaseinstancevariables,butyoumayneedtoinvoke
systemclassesandothercodethatisn’tcompiledusingARC.
Custom
Youcanstilluse
andotherrelatedfunctionswithCoreFoundation-styleobjects(seeManaging
Toll-FreeBridging).
Youcannotuse
Youcreateobjectsusing
theruntimetakescareofdeallocatingobjects.
YoucannotuseobjectpointersinCstructures.
Ratherthanusinga
instead.
Thereisnocasualcastingbetween
Youmustusespecialcaststhattellthecompileraboutobjectlifetime.YouneedtodothistocastbetweenObjective-CobjectsandCoreFoundationtypesthatyoupassasfunctionarguments.
Formoredetails,seeManaging
Toll-FreeBridging.
Youcannotuse
ARCprovides
efficientthan
Youcannotusememoryzones.
Thereisnoneedtouse
runtimeanyway.
Thekeywords
declaredpropertyattributes,asshowninthefollowingexamples.
UnderARC,
Youusethefollowinglifetimequalifiersforvariablesjustlikeyouwould,say,
therearenostrongreferencestotheobject.(指定不保留引用对象的引用。如果没有对对象的强引用,则弱引用将设置为零。)
therearenostrongreferencestotheobject.Iftheobjectitreferencesisdeallocated,thepointerisleftdangling.指定一个引用,该引用不保留引用对象的生存状态,并且在没有对对象进行强引用时不会将其设置为零。如果引用的对象被释放,指针是摇摇欲坠。)
Youshoulddecoratevariablescorrectly.Whenusingqualifiersinanobjectvariabledeclaration,thecorrectformatis:
forexample:
Othervariantsaretechnicallyincorrectbutare“forgiven”bythecompiler.Tounderstandtheissue,seehttp://cdecl.org/.
Takecarewhenusing
Although
deallocated.Thelogstatementshowsthat
Youalsoneedtotakecarewithobjectspassedbyreference.Thefollowingcodewillwork:
However,theerrordeclarationisimplicitly:
andthemethoddeclarationwouldtypicallybe:
Thecompilerthereforerewritesthecode:
Themismatchbetweenthelocalvariabledeclaration(
causesthecompilertocreatethetemporaryvariable.Youcangettheoriginalpointerbydeclaringtheparameter
ofa
Youcanuselifetimequalifierstoavoidstrongreferencecycles.Forexample,typicallyifyouhaveagraphofobjectsarrangedinaparent-childhierarchyandparentsneedtorefertotheirchildrenandviceversa,thenyoumaketheparent-to-childrelationship
strongandthechild-to-parentrelationshipweak.Othersituationsmaybemoresubtle,particularlywhentheyinvolveblock
objects.
Inmanualreferencecountingmode,
InARCmode,
likeallothervalues).TogetthemanualreferencecountingmodebehaviorunderARC,youcoulduse
however,havinganon-retainedvariableisdangerous(becauseitcandangle)andisthereforediscouraged.Twobetteroptionsaretoeitheruse
youdon’tneedtosupportiOS4orOSXv10.6),orsetthe
breaktheretaincycle.
Thefollowingcodefragmentillustratesthisissueusingapatternthatissometimesusedinmanualreferencecounting.
Asdescribed,instead,youcanusea
to
Alternatively,youcanuseatemporary
Fornon-trivialcycles,however,youshoulduse:
UseLifetimeQualifierstoAvoidStrongReferenceCycles
Youcanuselifetimequalifierstoavoidstrongreferencecycles.Forexample,typicallyifyouhaveagraphofobjectsarrangedinaparent-childhierarchyandparentsneedtorefertotheirchildrenandviceversa,thenyoumaketheparent-to-childrelationship
strongandthechild-to-parentrelationshipweak.Othersituationsmaybemoresubtle,particularlywhentheyinvolveblock
objects.
Inmanualreferencecountingmode,
InARCmode,
likeallothervalues).TogetthemanualreferencecountingmodebehaviorunderARC,youcoulduse
however,havinganon-retainedvariableisdangerous(becauseitcandangle)andisthereforediscouraged.Twobetteroptionsaretoeitheruse
youdon’tneedtosupportiOS4orOSXv10.6),orsetthe
breaktheretaincycle.
Thefollowingcodefragmentillustratesthisissueusingapatternthatissometimesusedinmanualreferencecounting.
Asdescribed,instead,youcanusea
to
Alternatively,youcanuseatemporary
Fornon-trivialcycles,however,youshoulduse:
Insomecasesyoucanuse
Thiscan,however,becomeimpracticalfornontrivialcyclesbecauseitcanbehardorimpossibletovalidatethatthe
validandstillpointstothesameobjectinquestion.
InmanyCocoaapplications,youneedtouseCoreFoundation-styleobjects,whetherfromtheCoreFoundationframeworkitself(suchas
orfromframeworksthatadoptCoreFoundationconventionssuchasCoreGraphics(youmightusetypeslike
ThecompilerdoesnotautomaticallymanagethelifetimesofCoreFoundationobjects;youmustcall
thecorrespondingtype-specificvariants)asdictatedbytheCoreFoundationmemorymanagementrules(seeMemory
ManagementProgrammingGuideforCoreFoundation).
IfyoucastbetweenObjective-CandCoreFoundation-styleobjects,youneedtotellthecompilerabouttheownershipsemanticsoftheobjectusingeitheracast(definedin
oraCoreFoundation-stylemacro(definedin
pointertoaCoreFoundationpointerandalsotransfersownershiptoyou.
Youareresponsibleforcalling
pointertoObjective-CandalsotransfersownershiptoARC.
ARCisresponsibleforrelinquishingownershipoftheobject.
Forexample,ifyouhadcodelikethis:
youcouldreplaceitwith:
Runloop
OSX/iOS系统中,提供了两个这样的对象:NSRunLoop和CFRunLoopRef。
CFRunLoopRef是在CoreFoundation框架内的,它提供了纯C函数的API,所有这些API都是线程安全的。
NSRunLoop是基于CFRunLoopRef的封装,提供了面向对象的API,但是这些API不是线程安全的。
小结:我们的RunLoop要想工作,必须要让它存在一个Item(source,observer或者timer),主线程之所以能够一直存在,并且随时准备被唤醒就是应为系统为其添加了很多Item
小结:我们的RunLoop要想工作,必须要让它存在一个Item(source,observer或者timer),主线程之所以能够一直存在,并且随时准备被唤醒就是应为系统为其添加了很多Item
小结:当performselector在后台线程中执行的时候,这个线程必须有一个开启的runLoop
小结:正常情况下,后台线程执行完任务之后就处于死亡状态,我们要避免这种情况的发生可以利用RunLoop,并且给它一个Source这样来保证线程依旧还在
苹果用RunLoop实现的功能都有什么:关于网络请求,GCD,定时器,performSelecter,界面更行,手势识别,AutoreleasePool,
Runloop的实际应用:AFNetworking,AsyncDisplayKit
Table3-1Predefined
Table3-2Performingselectorsonotherthreads
Figure3-2Operating
acustominputsource
Listing3-10CreatingandschedulingtimersusingNSTimer
Table4-1Locktypes
Anoperationobjectisaninstanceofthe
usetoencapsulateworkyouwantyourapplicationtoperform.The
doanyusefulwork.Despitebeingabstract,thisclassdoesprovideasignificantamountofinfrastructuretominimizetheamountofworkyouhavetodoinyourownsubclasses.Inaddition,theFoundationframeworkprovidestwoconcretesubclassesthatyou
canuseas-iswithyourexistingcode.Table2-1liststheseclasses,alongwithasummaryofhowyouuseeachone.
Table2-1OperationclassesoftheFoundationframework
Listing2-1Creatingan
Listing2-2Creatingan
Ataminimum,everyoperationobjectshouldimplementatleastthefollowingmethods:
Acustominitializationmethod
Youneedacustominitializationmethodtoputyouroperationobjectintoaknownstateandacustom
methodsasneeded,ofcourse,suchasthefollowing:
Custommethodsthatyouplantocallfromtheimplementationofyour
Accessormethodsforsettingdatavaluesandaccessingtheresultsoftheoperation
Methodsofthe
toallowyoutoarchiveandunarchivetheoperationobject
Listing2-3Definingasimpleoperationobject
Tocreateaqueue,youallocateitinyourapplicationasyouwouldanyotherobject:
Notifications
An
Theobjectisanyobjectthattheposterofthenotificationwantstosendtoobserversofthatnotification—typicallytheobjectthatpostedthenotificationitself.Thedictionarymaycontainadditionalinformationabouttheevent.
Cocoaincludestwotypesofnotificationcenters:
The
The
Exceptions
an
A
ashortstringthatisusedtouniquelyidentifytheexception.Thenameisrequired.
A
alongerstringthatcontainsa“human-readable”reasonfortheexception.Thereasonisrequired.
Anoptionaldictionary(
usedtosupplyapplication-specificdatatotheexceptionhandler.Forexample,ifthereturnvalueofamethodcausesanexceptiontoberaised,youcouldpassthereturnvaluetotheexceptionhandlerthrough
The
constituteacontrolstructure.Thesectionofcodebetweenthebracesin
isalocalexceptionhandler;the
1,thenormalflowofprogramexecutionismarkedbythegrayarrow;thecodewithinthelocalexceptionhandlerisexecutedonlyifanexceptionisthrown—eitherbythelocalexceptionhandlingdomainoronefurtherdownthecallsequence.Thethrowing
(orraising)ofanexceptioncausesprogramcontroltojumptothefirstexecutablelineofthelocalexceptionhandler.Aftertheexceptionishandled,control“fallsthrough”tothe
ifnoexceptionisthrown,controljumpsfromthe
Figure1Flowofexceptionhandlingusingcompilerdirectives
Listing1Handlinganexceptionusingcompilerdirectives
Usingitastheargumentofa
Sendingita
Thefollowingexampleshowshowyouthrowanexceptionusingthe
iscommentedout):
Listing1Throwingandre-throwinganexception
Figure1Control
flowwithnestedexceptionhandlers—usingdirectives
链式编程思想/链式编程?
链式编程在我们iOS中并不陌生的,比如OC中的Masonry和Swift中的SnapKit第三方就是利用的链式编程,链式编程就是把多个操作多行代码通过操作符号(通常是点.)连成一句执行的代码。来降低代码的重复度,使起看起来更易读。
对ReactiveNative,reactiveCocoa了解?
MVC,MVVM具体的实现?
IM通信机制实现。
Runtime>项目在runtime的时候进行了那些操作。
GCD简介
//01:队列的唯一标识,采用反域名形式
//02:队列的属性类型,也就是标识这个队列是串行队列还是并行队列
//(1)自己创建的串行队列中添加异步任务是在子线程中完成任务;
//(2)自己创建的串行队列中添加同步任务是在主线程中完成任务;
//总结:同步任务:不管在哪一个队列中都是主线程中执行,但是不能将其添加到系统自带的串行队列中;
//异步任务:在自己创建的串行队列中,在子线程中执行,如果是系统创建的队列在主线程中执行;
#defineMIN(A,B)((A)<(B)?(A):(B))
2,重写setter方法用于完成@property(nonatommic,retain)Object*obj;
-(void)setObj:(Class*)objValue{
if(obj!=objValue){
[objrelease];
obj=[valueretain];
}
}
3.assign,retain,copy区别,以及ARC下的weak,strong;
assign:简单赋值,不更改索引计数
copy:建立一个索引计数为1的对象,然后释放旧对象
retain:释放旧的对象,将旧对象的值赋予输入对象,再提高输入对象的索引计数为1;
Copy其实是建立了一个相同的对象,而retain不是:
比如一个NSString对象,地址为0×1111,内容为@”STR”
Copy到另外一个NSString之后,地址为0×2222,内容相同,新的对象retain为1,旧有对象没有变化
retain到另外一个NSString之后,地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的retain值+1
也就是说,retain是指针拷贝,copy是内容拷贝。在拷贝之前,都会释放旧的对象。
*使用assign:
对基础数据类型(NSInteger)和C数据类型(int,float,double,char,等)
*使用copy:对NSString
*使用retain:对其他NSObject和其子类
ARC(Automatic
ReferenceCounting)。简单地说,就是代码中自动加入了retain/release,原先需要手动添加的用来处理内存管理的引用计数的代码可以自动地由编译器完成了。
苹果官网只是图
4.release,autorelease,autoreleasepool,ARC,是什么,他们的机制以及区别;
5.使用block或使用delegate完成委托有什么优缺点,重写和重载;
重载(overload):函数名相同,函数的参数列表不同(包括参数个数和参数类型),至于返回类型可同可不同。重载既可以发生在同一个类的不同函数之间,也可发生在父类子类的继承关系之间,其中发生在父类子类之间时要注意与重写区分开。
重写(override):发生于父类和子类之间,指的是子类不想继承使用父类的方法,通过重写同一个函数的实现实现对父类中同一个函数的覆盖,因此又叫函数覆盖。注意重写的函数必须和父类一模一样,包括函数名、参数个数和类型以及返回值,只是重写了函数的实现,这也是和重载区分开的关键。
首先要了解什么是委托模式,委托模式在iOS中大量应用,其在设计模式中是适配器模式中的对象适配器,Objective-C中使用id类型指向一切对象,使委托模式在iOS中的实现更为方便。了解委托模式的细节:
使用block实现委托模式,其优点是回调的block代码块定义在委托对象函数内部,使代码更为紧凑;
1.有多个相关方法。假如每个方法都设置一个block,这样会更麻烦。而delegate让多个方法分成一组,只需要设置一次,就可以多次回调。当多于3个方法时就应该优先采用delegate。
比如一个网络类,假如只有成功和失败两种情况,每个方法可以设计成单独block。但假如存在多个方法,比如有成功、失败、缓存、https验证,网络进度等等,这种情况下,delegate就要比block要好。
2.为了避免循环引用,也可以使用
delegate。使用block时稍微不注意就形成循环引用,导致对象释放不了。这种循环引用,一旦出现就比较难检查出来。而delegate的方法是分离开的,并不会引用上下文,因此会更安全些。
6.NSArray,NSMutableArray的区别,Copy,MutableCopy的区别,
copy与retain的区别:copy是创建一个新对象,retain是创建一个指针,引用对象计数加1。Copy属性表示两个对象内容相同,新的对象retain为1,与旧有对象的引用计数无关,旧有对象没有变化。copy减少对象对上下文的依赖。
对于系统的非容器类对象,对一不可变对象复制,copy是指针复制(浅拷贝)和mutableCopy就是对象复制(深拷贝)。如果是对可变对象复制,都是深拷贝,但是copy返回的对象是不可变的。
对于系统的容器类对象,以上规则同样适用,但是容器内的元素全部都是浅拷贝,也就是说所有的元素拷贝的仅仅是指针,内存没被复制。
1.copy:不可变复制
2.mutableCopy:可变复制
对receiver的要求不一样
1.copy:receiver必须实现NSCopying协议
2.mutableCopy:receiver必须实现NSMutableCopying协议
执行效果不一样
1.如果receiver是不可变容器
1)copy:返回receiver,并且receiver的引用计数加1,等效于retain
2)mutableCopy:由receiver中的数据构造一个新的可变实例
2.如果receiver是可变容器
1)copy:由receiver中的数据构造一个新的不可变实例
2)mutableCopy:由receiver中的数据构造一个新的可变实例
3.原因
为什么SDK对不同类型的receiver会产生如此多种结果。主要考虑以下方面
1)达到定义要求的效果。(参考上面定义中的描述)
2)尽量节省资源开销。
基于这第2)点。所以当receiver是不可变容器的时候,接收到copy消息时。只要达到retain的效果就可以了。这样一方面可以满足定义的要求,另一主面可以节省资源。
4.特定应用
1)为什么property声明中只有“copy”特性而没有“mutableCopy”特性。这是由于当声明property为"copy"特性时,系统会自动根据receiver的特点决定使用copy(已含retain的情况)还是mutableCopy。
2)所以对于容器类的property特性一般使用“copy”而不使用“retain”,交由系统根据receiver自己决定以达到最好的效果。
NSArray可以看成是线程安全,NAMutablearray可变数组非线程安全
功能单一,实现起来会更简单。
没有修改的数据的接口,就从根源防止了数据无意中被修改。
因为不会被修改,更容易被缓存复用。
因为不可变,只读,多线程访问的时候,也不会发生一边读一边写的情况,也就没有同步的问题,也就不用上锁。
7,NSNotification和KVO的区别和用法是什么?什么时候应该使用通知,什么时候应该使用KVO,它们的实现上有什么区别吗?如果用protocol和delegate(或者delegate的Array)来实现类似的功能可能吗?如果可能,会有什么潜在的问题?如果不能,为什么?
NSNotification是通知模式在
coding)的,KVC是一个通过属性名访问属性变量的机制。例如将Model层的变化,通知到多个Controller对象时,可以使用NSNotification;如果是只需要观察某个对象的某个属性,可以使用KVO。
对于委托模式,在设计模式中是对象适配器模式,其是delegate是指向某个对象的,这是一对一的关系,而在通知模式中,往往是一对多的关系。委托模式,从技术上可以现在改变delegate指向的对象,但不建议这样做,会让人迷惑,如果一个delegate对象不断改变,指向不同的对象。
7Runtime是什么!
RunTime简称运行时。就是系统在运行的时候的一些机制,其中最主要的是消息机制。对于C语言,函数的调用在编译的时候会决定调用哪个函数(C语言的函数调用请看这里)。编译完成之后直接顺序执行,无任何二义性。OC的函数调用成为消息发送。属于动态调用过程。在编译的时候并不能决定真正调用哪个函数(事实证明,在编
译阶段,OC可以调用任何函数,即使这个函数并未实现,只要申明过就不会报错。而C语言在编译阶段就会报错)。只有在真正运行的时候才会根据函数的名称找到对应的函数来调用。
Objective-C语言将许多决策可以在编译时和运行时链接的时间。只要有可能,它的东西动态。这意味着,语言需要的不仅仅是一个编译器,而且运行时系统执行编译后的代码。运行时系统作为一种用于Objective-C语言的操作系统;它使语言文字工作。
这个文件看
NSObject类和Objective-C程序如何与交互运行时系统。特别是,它探讨了范式的动态加载新的类在运行时,转发消息到其他对象。它还提供了有关如何你可以找到有关对象的信息在您的程序运行。
All
char*intheruntimeAPIshouldbeconsideredtohaveUTF-8encoding.
Forthemostpart,theruntimesystemworksautomaticallyandbehindthescenes.YouuseitjustbywritingandcompilingObjective-Csourcecode.
当你编译包含Objective-C类和方法的代码,编译器创建的数据结构和函数,实现语言的动态特性要求。数据结构捕捉类别定义和协议声明发现信息;包括讨论中的类和协议的对象定义一个类和协议进入Objective-C编程语言,以及方法的选择,实例变量的模板,和其他信息从源代码中提取。主要的运行时功能是发送消息,如
运行时系统是一个动态共享库的一个公共接口由一组函数和数据位于目录的头文件的结构
objc/usr/include/。许多这些功能允许你使用纯C复制什么编译器就当你编写Objective-C代码。通过对功能的方法的基础上,其他形式的出口
NSObject类这些功能使得它可以发展其他接口的运行系统和生产工具,增加发展环境;他们不需要编程时在Objective-C。然而,一些运行时功能有时是有用的写作一个Objective-C程序时。所有的这些功能是记录
1.1Theobjc_msgSendFunction
InObjective-C,messagesaren’t
boundtomethodimplementationsuntilruntime.Thecompilerconvertsamessageexpression
[receivermessage]
接收到类名的调用后可以转化为消息底层的发送机制,或多参数的发送
objc_msgSend(receiver,selector)
objc_msgSend(receiver,selector,arg1,arg2,...)
消息传递函数为动态绑定做所有必要的工作:
Itfirstfindstheprocedure(methodimplementation)thattheselectorrefersto.Sincethesamemethodcanbeimplementeddifferently
byseparateclasses,thepreciseprocedurethatitfindsdependsontheclassofthereceiver.
Itthencallstheprocedure,passingitthereceivingobject(apointertoitsdata),alongwithanyargumentsthatwerespecifiedforthemethod.
Finally,itpassesonthereturnvalueoftheprocedureasitsownreturnvalue.
消息传递的关键在于编译器为每个类和对象构建的结构。每个阶级结构包括这两个基本要素:
Apointertothesuperclass.
Aclassdispatchtable.Thistablehasentriesthatassociatemethod
selectorswiththeclass-specificaddressesofthemethodstheyidentify.Theselectorforthe
setOrigin::methodisassociatedwiththeaddressof(theprocedure
thatimplements)
setOrigin::,theselectorforthe
displaymethod
isassociatedwith
display’saddress,andsoon.
Figure
3-1MessagingFramework
Whenamessageissenttoanobject,themessagingfunctionfollowstheobject’s
isapointer
totheclassstructurewhereitlooksupthemethodselectorinthedispatchtable.Ifitcan’tfindtheselectorthere,
objc_msgSendfollowsthepointerto
thesuperclassandtriestofindtheselectorinitsdispatchtable.Successivefailurescause
objc_msgSendtoclimbtheclasshierarchyuntilitreachesthe
NSObjectclass.
Onceitlocatestheselector,thefunctioncallsthemethodenteredinthetableandpassesitthereceivingobject’sdatastructure.
Thisisthewaythatmethodimplementationsarechosenatruntime—or,inthejargonofobject-orientedprogramming,thatmethodsaredynamicallyboundtomessages.
加速消息传递过程中,运行时系统缓存使用选择器和地址的方法。有一个单独的缓存中为每个类,它可以包含继承的方法以及方法的选择器中定义的类。之前搜索调度表,收到的消息传递程序首先检查缓存对象的类(在理论,一种方法是使用一次可能会再次使用)。如果选择器的方法是在缓存中,消息传递是仅略低于一个函数调用。一旦一个程序被运行足够长的时间来“热身”其缓存,几乎所有它发送的消息找到缓存的方法。缓存生长在程序运行时动态地适应新的消息。
UsingHiddenArguments
Whenfindsobjc_msgSend
theprocedurethatimplementsamethod,itcallstheprocedureandpassesitalltheargumentsinthemessage.Italsopassestheproceduretwohiddenarguments:
Thereceivingobject
Theselectorforthemethod
-strange |
{ |
idtarget=getTheReceiver(); |
SELmethod=getTheMethod(); |
if(target==self||method==_cmd) |
returnnil; |
return[targetperformSelector:method]; |
} |
GettingaMethodAddress
为了规避动态绑定的唯一方法是得到方法的地址仿佛它是一个函数调用,它直接。这可能是适当的在罕见的情况下,当一个特定的方法将陆续进行了很多次,你想避免消息每次执行方法的开销。一个定义的方法
NSObject类,
methodforselector:,你可以要求一个指针来实现的方法,然后用指针调用程序。指针,
methodforselector:退货必须精心铸造的应有功能型。返回与参数类型应包括在投。
下面的例子显示了如何的程序实现
setfilled:方法可称为
void(*setter)(id,SEL,BOOL); |
inti; |
setter=(void(*)(id,SEL,BOOL))[target |
methodForSelector:@selector(setFilled:)]; |
for(i=0;i<1000;i++) |
setter(targetList[i],@selector(setFilled:),YES); |
自己)和方法选择器(
_ CMD)。这些观点都隐藏在方法的语法但必须明确当方法称为一个函数。
使用
methodforselector:为了规避动态绑定可以节省大部分时间所需的信息。然而,储蓄将明显只有在特定消息重复多次,在
为环上面
请注意,
methodforselector:是由可可的运行时系统提供的;它不是一个功能的Objective-C语言本身。
DynamicMethodResolution
Therearesituationswhereyoumightwanttoprovideanimplementationofamethoddynamically.Forexample,theObjective-Cdeclaredpropertiesfeature(seeDeclaredPropertiesinTheObjective-CProgrammingLanguage)includesthe
@dynamicdirective:
@dynamicpropertyName; |
andresolveInstanceMethod:
toresolveClassMethod:
dynamicallyprovideanimplementationforagivenselectorforaninstanceandclassmethodrespectively.
AnObjective-CmethodissimplyaCfunctionthattakeatleasttwoarguments—
selfand
_cmd.
Youcanaddafunctiontoaclassasamethodusingthefunction
.class_addMethod
Therefore,giventhefollowingfunction:
voiddynamicMethodIMP(idself,SEL_cmd){ |
//implementation.... |
} |
resolveThisMethodDynamically)using
resolveInstanceMethod:like
this:
@implementationMyClass |
+(BOOL)resolveInstanceMethod:(SEL)aSEL |
{ |
if(aSEL==@selector(resolveThisMethodDynamically)){ |
class_addMethod([selfclass],aSEL,(IMP)dynamicMethodIMP,"v@:"); |
returnYES; |
} |
return[superresolveInstanceMethod:aSEL]; |
} |
@end |
DynamicLoading
一个Objective-C程序可以加载和链接新课和类别而它的运行。新的代码加入到程序和处理相同的类和类开始加载。动态加载可以用来做很多不同的事情。例如,在系统偏好设置中的各个模块的动态加载。
在可可的环境,动态加载通常用于允许应用程序定制。别人可以写你的程序在运行时加载多界面生成器加载自定义调色板和OSX系统偏好设置自定义模块加载应用程序的偏好。加载模块扩展您的应用程序可以做什么。它们有助于它的方式,你允许但不可预期的或定义自己。你提供的框架,但其他人提供的代码。
虽然是一个运行时函数的执行,在Objective-CMach-O文件动态加载模块(
objc_loadmodules,定义
objc可可的)
/objc负荷。H
NSBundle类提供了一个面向对象的动态加载和相关服务集成更方便的接口。看到
在信息的基础架构参考类规范NSBundle
NSBundle类及其使用。看到OS
X的ABIMach-O文件格式参考用于信息是Mach-O文件。
遇到一个方法调用时,编译器会生成一个调用的一个函数
Whenitencountersamethodcall,thecompilergeneratesacalltooneofthefunctions
objc_msgSend,
objc_msgSend_stret,
objc_msgSendSuper,
or
objc_msgSendSuper_stret.Messagessenttoanobject’ssuperclass(usingthe
superkeyword)
aresentusing
objc_msgSendSuper;othermessagesaresentusing
objc_msgSend.
Methodsthathavedatastructuresasreturnvaluesaresentusing
objc_msgSendSuper_stretand
objc_msgSend_stret.
8ARC?
ARC的工作原理是编译时添加代码,以确保对象在必要的时候生存,并不是你记得的什么时候release,return和autorelease,ARC对你的对象的生存期的要求和自动插入适当的内存管理当你在编译的时候,编译器也会为你生成合适的dealloc方法,
Acompleteandcorrectimplementationofa
Personclassmightlooklikethis:
@interfacePerson:NSObject |
@propertyNSString*firstName; |
@propertyNSString*lastName; |
@propertyNSNumber*yearOfBirth; |
@propertyPerson*spouse; |
@end |
@implementationPerson |
@end |
strongbydefault;the
strongattribute
isdescribedinARC
IntroducesNewLifetimeQualifiers.)
UsingARC,youcouldimplementacontrivedmethodlikethis:
-(void)contrived{ |
Person*aPerson=[[Personalloc]init]; |
[aPersonsetFirstName:@"William"]; |
[aPersonsetLastName:@"Dudney"]; |
[aPersonsetYearOfBirth:[[NSNumberalloc]initWithInteger:2011]]; |
NSLog(@"aPerson:%@",aPerson); |
} |
Personnorthe
NSNumberobjects
areleaked.
Youcouldalsosafelyimplementa
takeLastNameFrom:methodof
Personlike
this:
-(void)takeLastNameFrom:(Person*)person{ |
NSString*oldLastname=[selflastName]; |
[selfsetLastName:[personlastName]]; |
NSLog(@"Lastnamechangedfrom%@to%@",oldLastname,[selflastName]); |
} |
oldLastNameisnotdeallocatedbeforethe
NSLogstatement.
ARC的一些新的规则:
工作时,arc对一些新的规章制度,不使用其他编译模式。该规则旨在提供一个完全可靠的内存管理模型;在某些情况下,他们只是执行的最佳实践,在一些可以简化代码或是明显的你不必处理内存管理的推论。如果你违反了这些规则,你会得到一个即时编译时错误,不是一个微妙的错误,可能会在运行时明显。
Youcannotexplicitlyinvoke
dealloc,orimplementorinvoke
retain,
release,
retainCount,
or
autorelease.
Theprohibitionextendstousing
@selector(retain),
@selector(release),
andsoon.
Youmayimplementa
deallocmethodifyouneedtomanageresourcesotherthanreleasing
instancevariables.Youdonothaveto(indeedyoucannot)releaseinstancevariables,butyoumayneedtoinvoke
[systemClassInstancesetDelegate:nil]on
systemclassesandothercodethatisn’tcompiledusingARC.
Custom
deallocmethodsinARCdonotrequireacallto
[super dealloc](itactuallyresultsinacompilererror).Thechainingtosuperisautomatedandenforcedbythecompiler.
Youcanstilluse
CFRetain,
CFRelease,
andotherrelatedfunctionswithCoreFoundation-styleobjects(seeManaging
Toll-FreeBridging).
Youcannotuse
NSAllocateObjector
NSDeallocateObject.
Youcreateobjectsusing
;alloc
theruntimetakescareofdeallocatingobjects.
YoucannotuseobjectpointersinCstructures.
Ratherthanusinga
struct,youcancreateanObjective-Cclasstomanagethedata
instead.
Thereisnocasualcastingbetween
idand
void*.
Youmustusespecialcaststhattellthecompileraboutobjectlifetime.YouneedtodothistocastbetweenObjective-CobjectsandCoreFoundationtypesthatyoupassasfunctionarguments.
Formoredetails,seeManaging
Toll-FreeBridging.
Youcannotuse
objects.NSAutoreleasePool
ARCprovides
@autoreleasepoolblocksinstead.Thesehaveanadvantageofbeingmore
efficientthan
NSAutoreleasePool.
Youcannotusememoryzones.
Thereisnoneedtouse
NSZoneanymore—theyareignoredbythemodernObjective-C
runtimeanyway.
PropertyAttributes
Thekeywordsweakand
strongareintroducedasnew
declaredpropertyattributes,asshowninthefollowingexamples.
//Thefollowingdeclarationisasynonymfor:@property(retain)MyClass*myObject; |
@property(strong)MyClass*myObject; |
//Thefollowingdeclarationissimilarto"@property(assign)MyClass*myObject;" |
//exceptthatiftheMyClassinstanceisdeallocated, |
//thepropertyvalueissettonilinsteadofremainingasadanglingpointer. |
@property(weak)MyClass*myObject; |
strongisthedefaultforobjecttypes.
VariableQualifiers
Youusethefollowinglifetimequalifiersforvariablesjustlikeyouwould,say,const.
__strong |
__weak |
__unsafe_unretained |
__autoreleasing |
__strongisthedefault.Anobjectremains“alive”aslongasthereisastrongpointertoit.(只要有一个指向它的强指针,对象仍然是“活着的”。)
__weakspecifiesareferencethatdoesnotkeepthereferencedobjectalive.Aweakreferenceissetto
nilwhen
therearenostrongreferencestotheobject.(指定不保留引用对象的引用。如果没有对对象的强引用,则弱引用将设置为零。)
__unsafe_unretainedspecifiesareferencethatdoesnotkeepthereferencedobjectaliveandisnotsetto
nilwhen
therearenostrongreferencestotheobject.Iftheobjectitreferencesisdeallocated,thepointerisleftdangling.指定一个引用,该引用不保留引用对象的生存状态,并且在没有对对象进行强引用时不会将其设置为零。如果引用的对象被释放,指针是摇摇欲坠。)
__autoreleasingisusedtodenoteargumentsthatarepassedbyreference(
id *)andareautoreleasedonreturn.
Youshoulddecoratevariablescorrectly.Whenusingqualifiersinanobjectvariabledeclaration,thecorrectformatis:
ClassName*qualifiervariableName; |
MyClass*__weakmyWeakReference; |
MyClass*__unsafe_unretainedmyUnsafeReference; |
Takecarewhenusing
__weakvariablesonthestack.Considerthefollowingexample:
NSString*__weakstring=[[NSStringalloc]initWithFormat:@"FirstName:%@",[selffirstName]]; |
NSLog(@"string:%@",string); |
stringisusedaftertheinitialassignment,thereisnootherstrongreferencetothestringobjectatthetimeofassignment;itisthereforeimmediately
deallocated.Thelogstatementshowsthat
stringhasanullvalue.(Thecompilerprovidesawarninginthissituation.)
Youalsoneedtotakecarewithobjectspassedbyreference.Thefollowingcodewillwork:
NSError*error; |
BOOLOK=[myObjectperformOperationWithError:&error]; |
if(!OK){ |
//Reporttheerror. |
//... |
NSError*__stronge; |
-(BOOL)performOperationWithError:(NSError*__autoreleasing*)error; |
NSError*__strongerror; |
NSError*__autoreleasingtmp=error; |
BOOLOK=[myObjectperformOperationWithError:&tmp]; |
error=tmp; |
if(!OK){ |
//Reporttheerror. |
//... |
__strong)andtheparameter(
__autoreleasing)
causesthecompilertocreatethetemporaryvariable.Youcangettheoriginalpointerbydeclaringtheparameter
id__strong*whenyoutaketheaddress
ofa
__strongvariable.Alternativelyyoucandeclarethevariableas
__autoreleasing.
UseLifetimeQualifierstoAvoidStrongReferenceCycles
Youcanuselifetimequalifierstoavoidstrongreferencecycles.Forexample,typicallyifyouhaveagraphofobjectsarrangedinaparent-childhierarchyandparentsneedtorefertotheirchildrenandviceversa,thenyoumaketheparent-to-childrelationshipstrongandthechild-to-parentrelationshipweak.Othersituationsmaybemoresubtle,particularlywhentheyinvolveblock
objects.
Inmanualreferencecountingmode,
__blockidx;hastheeffectofnotretaining
x.
InARCmode,
__blockidx;defaultstoretaining
x(just
likeallothervalues).TogetthemanualreferencecountingmodebehaviorunderARC,youcoulduse
__unsafe_unretained__blockidx;.Asthename
__unsafe_unretainedimplies,
however,havinganon-retainedvariableisdangerous(becauseitcandangle)andisthereforediscouraged.Twobetteroptionsaretoeitheruse
__weak(if
youdon’tneedtosupportiOS4orOSXv10.6),orsetthe
__blockvalueto
nilto
breaktheretaincycle.
Thefollowingcodefragmentillustratesthisissueusingapatternthatissometimesusedinmanualreferencecounting.
MyViewController*myController=[[MyViewControlleralloc]init…]; |
//... |
myController.completionHandler=^(NSIntegerresult){ |
[myControllerdismissViewControllerAnimated:YEScompletion:nil]; |
}; |
[selfpresentViewController:myControlleranimated:YEScompletion:^{ |
[myControllerrelease]; |
}]; |
__blockqualifierandsetthe
myControllervariable
to
nilinthecompletionhandler:
MyViewController*__blockmyController=[[MyViewControlleralloc]init…]; |
//... |
myController.completionHandler=^(NSIntegerresult){ |
[myControllerdismissViewControllerAnimated:YEScompletion:nil]; |
myController=nil; |
}; |
__weakvariable.Thefollowingexampleillustratesasimpleimplementation:
MyViewController*myController=[[MyViewControlleralloc]init…]; |
//... |
MyViewController*__weakweakMyViewController=myController; |
myController.completionHandler=^(NSIntegerresult){ |
[weakMyViewControllerdismissViewControllerAnimated:YEScompletion:nil]; |
}; |
MyViewController*myController=[[MyViewControlleralloc]init…]; |
//... |
MyViewController*__weakweakMyController=myController; |
myController.completionHandler=^(NSIntegerresult){ |
MyViewController*strongMyController=weakMyController; |
if(strongMyController){ |
//... |
[strongMyControllerdismissViewControllerAnimated:YEScompletion:nil]; |
//... |
} |
else{ |
//Probablynothing... |
} |
}; |
strongandthechild-to-parentrelationshipweak.Othersituationsmaybemoresubtle,particularlywhentheyinvolveblock
objects.
Inmanualreferencecountingmode,
__blockidx;hastheeffectofnotretaining
x.
InARCmode,
__blockidx;defaultstoretaining
x(just
likeallothervalues).TogetthemanualreferencecountingmodebehaviorunderARC,youcoulduse
__unsafe_unretained__blockidx;.Asthename
__unsafe_unretainedimplies,
however,havinganon-retainedvariableisdangerous(becauseitcandangle)andisthereforediscouraged.Twobetteroptionsaretoeitheruse
__weak(if
youdon’tneedtosupportiOS4orOSXv10.6),orsetthe
__blockvalueto
nilto
breaktheretaincycle.
Thefollowingcodefragmentillustratesthisissueusingapatternthatissometimesusedinmanualreferencecounting.
MyViewController*myController=[[MyViewControlleralloc]init…]; |
//... |
myController.completionHandler=^(NSIntegerresult){ |
[myControllerdismissViewControllerAnimated:YEScompletion:nil]; |
}; |
[selfpresentViewController:myControlleranimated:YEScompletion:^{ |
[myControllerrelease]; |
}]; |
__blockqualifierandsetthe
myControllervariable
to
nilinthecompletionhandler:
MyViewController*__blockmyController=[[MyViewControlleralloc]init…]; |
//... |
myController.completionHandler=^(NSIntegerresult){ |
[myControllerdismissViewControllerAnimated:YEScompletion:nil]; |
myController=nil; |
}; |
__weakvariable.Thefollowingexampleillustratesasimpleimplementation:
MyViewController*myController=[[MyViewControlleralloc]init…]; |
//... |
MyViewController*__weakweakMyViewController=myController; |
myController.completionHandler=^(NSIntegerresult){ |
[weakMyViewControllerdismissViewControllerAnimated:YEScompletion:nil]; |
}; |
MyViewController*myController=[[MyViewControlleralloc]init…]; |
//... |
MyViewController*__weakweakMyController=myController; |
myController.completionHandler=^(NSIntegerresult){ |
MyViewController*strongMyController=weakMyController; |
if(strongMyController){ |
//... |
[strongMyControllerdismissViewControllerAnimated:YEScompletion:nil]; |
//... |
} |
else{ |
//Probablynothing... |
} |
}; |
__unsafe_unretainediftheclassisn’t
__weakcompatible.
Thiscan,however,becomeimpracticalfornontrivialcyclesbecauseitcanbehardorimpossibletovalidatethatthe
__unsafe_unretainedpointerisstill
validandstillpointstothesameobjectinquestion.
ManagingToll-FreeBridging
InmanyCocoaapplications,youneedtouseCoreFoundation-styleobjects,whetherfromtheCoreFoundationframeworkitself(suchasorCFArrayRef
)CFMutableDictionaryRef
orfromframeworksthatadoptCoreFoundationconventionssuchasCoreGraphics(youmightusetypeslike
andCGColorSpaceRef
).CGGradientRef
ThecompilerdoesnotautomaticallymanagethelifetimesofCoreFoundationobjects;youmustcall
andCFRetain
(orCFRelease
thecorrespondingtype-specificvariants)asdictatedbytheCoreFoundationmemorymanagementrules(seeMemory
ManagementProgrammingGuideforCoreFoundation).
IfyoucastbetweenObjective-CandCoreFoundation-styleobjects,youneedtotellthecompilerabouttheownershipsemanticsoftheobjectusingeitheracast(definedin
objc/runtime.h)
oraCoreFoundation-stylemacro(definedin
NSObject.h):
__bridgetransfersapointerbetweenObjective-CandCoreFoundationwithnotransferofownership.
__bridge_retainedor
CFBridgingRetaincastsanObjective-C
pointertoaCoreFoundationpointerandalsotransfersownershiptoyou.
Youareresponsibleforcalling
CFReleaseorarelatedfunctiontorelinquishownershipoftheobject.
__bridge_transferor
CFBridgingReleasemovesanon-Objective-C
pointertoObjective-CandalsotransfersownershiptoARC.
ARCisresponsibleforrelinquishingownershipoftheobject.
Forexample,ifyouhadcodelikethis:
-(void)logFirstNameOfPerson:(ABRecordRef)person{ |
NSString*name=(NSString*)ABRecordCopyValue(person,kABPersonFirstNameProperty); |
NSLog(@"Person'sfirstname:%@",name); |
[namerelease]; |
} |
-(void)logFirstNameOfPerson:(ABRecordRef)person{ |
NSString*name=(NSString*)CFBridgingRelease(ABRecordCopyValue(person,kABPersonFirstNameProperty)); |
NSLog(@"Person'sfirstname:%@",name); |
} |
OSX/iOS系统中,提供了两个这样的对象:NSRunLoop和CFRunLoopRef。
CFRunLoopRef是在CoreFoundation框架内的,它提供了纯C函数的API,所有这些API都是线程安全的。
NSRunLoop是基于CFRunLoopRef的封装,提供了面向对象的API,但是这些API不是线程安全的。
小结:我们的RunLoop要想工作,必须要让它存在一个Item(source,observer或者timer),主线程之所以能够一直存在,并且随时准备被唤醒就是应为系统为其添加了很多Item
小结:我们的RunLoop要想工作,必须要让它存在一个Item(source,observer或者timer),主线程之所以能够一直存在,并且随时准备被唤醒就是应为系统为其添加了很多Item
小结:当performselector在后台线程中执行的时候,这个线程必须有一个开启的runLoop
小结:正常情况下,后台线程执行完任务之后就处于死亡状态,我们要避免这种情况的发生可以利用RunLoop,并且给它一个Source这样来保证线程依旧还在
苹果用RunLoop实现的功能都有什么:关于网络请求,GCD,定时器,performSelecter,界面更行,手势识别,AutoreleasePool,
Runloop的实际应用:AFNetworking,AsyncDisplayKit
Mode | Name | Description |
---|---|---|
Default | (Cocoa) (Core Foundation) | Thedefaultmodeistheoneusedformostoperations.Mostofthetime,youshouldusethismodetostartyourrunloopandconfigureyourinputsources. |
Connection | (Cocoa) | Cocoausesthismodeinconjunctionwithobjects tomonitorreplies.Youshouldrarelyneedtousethismodeyourself. |
Modal | (Cocoa) | Cocoausesthismodetoidentifyeventsintendedformodalpanels. |
Eventtracking | (Cocoa) | Cocoausesthismodetorestrictincomingeventsduringmouse-draggingloopsandothersortsofuserinterfacetrackingloops. |
Commonmodes | (Cocoa) (Core Foundation) | Thisisaconfigurablegroupofcommonlyusedmodes.Associatinganinputsourcewiththismodealsoassociatesitwitheachofthemodesinthegroup.ForCocoaapplications,thissetincludesthedefault,modal,andeventtrackingmodesbydefault.CoreFoundation includesjustthedefaultmodeinitially.Youcanaddcustommodestothesetusingthe function |
Methods | Description |
---|---|
| Performsthespecifiedselectorontheapplication’smainthreadduringthatthread’snextrunloopcycle.Thesemethodsgiveyoutheoptionofblockingthecurrentthreaduntiltheselectorisperformed. |
| Performsthespecifiedselectoronanythreadforwhichyouhaveanobject. Thesemethodsgiveyoutheoptionofblockingthecurrentthreaduntiltheselectorisperformed. |
| Performsthespecifiedselectoronthecurrentthreadduringthenextrunloopcycleandafteranoptionaldelayperiod.Becauseitwaitsuntilthenextrunloopcycletoperformtheselector,thesemethodsprovideanautomaticminidelayfromthecurrently executingcode.Multiplequeuedselectorsareperformedoneafteranotherintheordertheywerequeued. |
| Letsyoucancelamessagesenttothecurrentthreadusingtheor method. |
-(void)threadMain |
{ |
//Theapplicationusesgarbagecollection,sonoautoreleasepoolisneeded. |
NSRunLoop*myRunLoop=[NSRunLoopcurrentRunLoop]; |
//Createarunloopobserverandattachittotherunloop. |
CFRunLoopObserverContextcontext={0,self,NULL,NULL,NULL}; |
CFRunLoopObserverRefobserver=CFRunLoopObserverCreate(kCFAllocatorDefault, |
kCFRunLoopAllActivities,YES,0,&myRunLoopObserver,&context); |
if(observer) |
{ |
CFRunLoopRefcfLoop=[myRunLoopgetCFRunLoop]; |
CFRunLoopAddObserver(cfLoop,observer,kCFRunLoopDefaultMode); |
} |
//Createandschedulethetimer. |
[NSTimerscheduledTimerWithTimeInterval:0.1target:self |
selector:@selector(doFireTimer:)userInfo:nilrepeats:YES]; |
NSIntegerloopCount=10; |
do |
{ |
//Runtherunloop10timestoletthetimerfire. |
[myRunLooprunUntilDate:[NSDatedateWithTimeIntervalSinceNow:1]]; |
loopCount--; |
} |
while(loopCount); |
} |
acustominputsource
Listing3-10CreatingandschedulingtimersusingNSTimer
NSRunLoop*myRunLoop=[NSRunLoopcurrentRunLoop]; |
//Createandschedulethefirsttimer. |
NSDate*futureDate=[NSDatedateWithTimeIntervalSinceNow:1.0]; |
NSTimer*myTimer=[[NSTimeralloc]initWithFireDate:futureDate |
interval:0.1 |
target:self |
selector:@selector(myDoFireTimer1:) |
userInfo:nil |
repeats:YES]; |
[myRunLoopaddTimer:myTimerforMode:NSDefaultRunLoopMode]; |
//Createandschedulethesecondtimer. |
[NSTimerscheduledTimerWithTimeInterval:0.2 |
target:self |
selector:@selector(myDoFireTimer2:) |
userInfo:nil |
repeats:YES]; |
Lock | Description |
---|---|
Mutex | Amutuallyexclusive(ormutex)lockactsasaprotectivebarrieraround aresource.Amutexisatypeofsemaphorethatgrantsaccesstoonlyonethreadatatime.Ifamutexisinuseandanotherthreadtriestoacquireit,thatthreadblocksuntilthemutexisreleasedbyitsoriginalholder.Ifmultiplethreadscompetefor thesamemutex,onlyoneatatimeisallowedaccesstoit. |
Recursivelock | Arecursivelockisavariantonthemutexlock.Arecursivelockallowsasinglethreadtoacquirethelockmultipletimesbeforereleasingit.Otherthreadsremainblockeduntiltheownerofthelockreleasesthelockthesamenumberoftimesitacquired it.Recursivelocksareusedduringrecursiveiterationsprimarilybutmayalsobeusedincaseswheremultiplemethodseachneedtoacquirethelockseparately. |
Read-writelock | Aread-writelockisalsoreferredtoasashared-exclusivelock.Thistypeoflockistypicallyusedinlarger-scaleoperationsandcansignificantlyimproveperformanceiftheprotecteddatastructureisreadfrequentlyandmodifiedonlyoccasionally.During normaloperation,multiplereaderscanaccessthedatastructuresimultaneously.Whenathreadwantstowritetothestructure,though,itblocksuntilallreadersreleasethelock,atwhichpointitacquiresthelockandcanupdatethestructure.Whilea writingthreadiswaitingforthelock,newreaderthreadsblockuntilthewritingthreadisfinished.Thesystemsupportsread-writelocksusingPOSIXthreadsonly.Formoreinformationonhowtousetheselocks,seethe pthreadman page. |
Distributedlock | Adistributedlockprovidesmutuallyexclusiveaccessattheprocesslevel.Unlikeatruemutex,adistributedlockdoesnotblockaprocessorpreventitfromrunning.Itsimplyreportswhenthelockisbusyandletstheprocessdecidehowtoproceed. |
Spinlock | Aspinlockpollsitslockconditionrepeatedlyuntilthatconditionbecomestrue.Spinlocksaremostoftenusedonmultiprocessorsystemswheretheexpectedwaittimeforalockissmall.Inthesesituations,itisoftenmoreefficienttopollthantoblock thethread,whichinvolvesacontextswitchandtheupdatingofthreaddatastructures.Thesystemdoesnotprovideanyimplementationsofspinlocksbecauseoftheirpollingnature,butyoucaneasilyimplementtheminspecificsituations.Forinformation onimplementingspinlocksinthekernel,seeKernel ProgrammingGuide. |
Double-checkedlock | Adouble-checkedlockisanattempttoreducetheoverheadoftakingalockbytestingthelockingcriteriapriortotakingthelock.Becausedouble-checkedlocksarepotentiallyunsafe,thesystemdoesnotprovideexplicitsupportforthemandtheiruseis discouraged. |
NSLock*arrayLock=GetArrayLock(); |
NSMutableArray*myArray=GetSharedArray(); |
idanObject; |
[arrayLocklock]; |
anObject=[myArrayobjectAtIndex:0]; |
[arrayLockunlock]; |
[anObjectdoSomething]; |
AboutOperationObjects
AnoperationobjectisaninstanceoftheNSOperationclass(intheFoundationframework)thatyou
usetoencapsulateworkyouwantyourapplicationtoperform.The
NSOperationclassitselfisanabstractbaseclassthatmustbesubclassedinorderto
doanyusefulwork.Despitebeingabstract,thisclassdoesprovideasignificantamountofinfrastructuretominimizetheamountofworkyouhavetodoinyourownsubclasses.Inaddition,theFoundationframeworkprovidestwoconcretesubclassesthatyou
canuseas-iswithyourexistingcode.Table2-1liststheseclasses,alongwithasummaryofhowyouuseeachone.
Class | Description |
---|---|
| Aclassyouuseas-istocreateanoperationobjectbasedonanobjectandselectorfromyourapplication. Youcanusethisclassincaseswhereyouhaveanexistingmethodthatalreadyperformstheneededtask.Becauseitdoesnotrequiresubclassing,youcanalsousethisclasstocreateoperationobjectsinamoredynamicfashion. Forinformationabouthowtousethisclass,seeCreating anNSInvocationOperationObject. |
| Aclassyouuseas-istoexecuteoneormoreblockobjectsconcurrently.Becauseitcanexecute morethanoneblock,ablockoperationobjectoperatesusingagroupsemantic;onlywhenalloftheassociatedblockshavefinishedexecutingistheoperationitselfconsideredfinished. Forinformationabouthowtousethisclass,seeCreating anNSBlockOperationObject.ThisclassisavailableinOSXv10.6andlater.Formoreinformationaboutblocks,seeBlocks ProgrammingTopics. |
| Thebaseclassfordefiningcustomoperationobjects.SubclassingNSOperationgivesyoucompletecontrolovertheimplementationofyourownoperations,including theabilitytoalterthedefaultwayinwhichyouroperationexecutesandreportsitsstatus. Forinformationabouthowtodefinecustomoperationobjects,seeDefining aCustomOperationObject. |
NSInvocationOperationobject
@implementationMyCustomClass |
-(NSOperation*)taskWithData:(id)data{ |
NSInvocationOperation*theOp=[[NSInvocationOperationalloc]initWithTarget:self |
selector:@selector(myTaskMethod:)object:data]; |
returntheOp; |
} |
//Thisisthemethodthatdoestheactualworkofthetask. |
-(void)myTaskMethod:(id)data{ |
//Performthetask. |
} |
@end |
NSBlockOperationobject
NSBlockOperation*theOp=[NSBlockOperationblockOperationWithBlock:^{ |
NSLog(@"Beginningoperation.\n"); |
//Dosomework. |
}]; |
PerformingtheMainTask
Ataminimum,everyoperationobjectshouldimplementatleastthefollowingmethods:Acustominitializationmethod
main
Youneedacustominitializationmethodtoputyouroperationobjectintoaknownstateandacustom
mainmethodtoperformyourtask.Youcanimplementadditional
methodsasneeded,ofcourse,suchasthefollowing:
Custommethodsthatyouplantocallfromtheimplementationofyour
mainmethod
Accessormethodsforsettingdatavaluesandaccessingtheresultsoftheoperation
Methodsofthe
protocolNSCoding
toallowyoutoarchiveandunarchivetheoperationobject
Listing2-3Definingasimpleoperationobject
@interfaceMyNonConcurrentOperation:NSOperation |
@propertyid(strong)myData; |
-(id)initWithData:(id)data; |
@end |
@implementationMyNonConcurrentOperation |
-(id)initWithData:(id)data{ |
if(self=[superinit]) |
myData=data; |
returnself; |
} |
-(void)main{ |
@try{ |
//DosomeworkonmyDataandreporttheresults. |
} |
@catch(...){ |
//Donotrethrowexceptions. |
} |
} |
@end |
NSOperationQueue*aQueue=[[NSOperationQueuealloc]init]; |
[aQueueaddOperation:anOp];//Addasingleoperation |
[aQueueaddOperations:anArrayOfOpswaitUntilFinished:NO];//Addmultipleoperations |
[aQueueaddOperationWithBlock:^{ |
/*Dosomething.*/ |
}]; |
An
NSNotificationobject(referredtoasanotification)containsaname,anobject,andanoptionaldictionary.Thenameisatagidentifyingthenotification.
Theobjectisanyobjectthattheposterofthenotificationwantstosendtoobserversofthatnotification—typicallytheobjectthatpostedthenotificationitself.Thedictionarymaycontainadditionalinformationabouttheevent.
Cocoaincludestwotypesofnotificationcenters:
The
NSNotificationCenterclassmanagesnotificationswithinasingleprocess.
The
NSDistributedNotificationCenterclassmanagesnotificationsacrossmultipleprocessesonasinglecomputer.
Model-View-Controller
Exceptions
an
NSExceptionobjectarethefollowing:
A
—name
ashortstringthatisusedtouniquelyidentifytheexception.Thenameisrequired.
A
—reason
alongerstringthatcontainsa“human-readable”reasonfortheexception.Thereasonisrequired.
Anoptionaldictionary(
)userInfo
usedtosupplyapplication-specificdatatotheexceptionhandler.Forexample,ifthereturnvalueofamethodcausesanexceptiontoberaised,youcouldpassthereturnvaluetotheexceptionhandlerthrough
userInfo.
The
@try,
@catch,and
@finallydirectives
constituteacontrolstructure.Thesectionofcodebetweenthebracesin
@tryistheexceptionhandlingdomain;thecodeina
@catchblock
isalocalexceptionhandler;the
@finallyblockofcodeisacommon“housekeeping”section.InFigure
1,thenormalflowofprogramexecutionismarkedbythegrayarrow;thecodewithinthelocalexceptionhandlerisexecutedonlyifanexceptionisthrown—eitherbythelocalexceptionhandlingdomainoronefurtherdownthecallsequence.Thethrowing
(orraising)ofanexceptioncausesprogramcontroltojumptothefirstexecutablelineofthelocalexceptionhandler.Aftertheexceptionishandled,control“fallsthrough”tothe
@finallyblock;
ifnoexceptionisthrown,controljumpsfromthe
@tryblocktothe
@finallyblock.
Figure1Flowofexceptionhandlingusingcompilerdirectives
Listing1Handlinganexceptionusingcompilerdirectives
-(void)endSheet:(NSWindow*)sheet |
{ |
BOOLsuccess=[predicateEditorViewcommitEditing]; |
if(success==YES){ |
@try{ |
[treeControllersetValue:[predicateEditorViewpredicate]forKeyPath:@"selection.predicate"]; |
} |
@catch(NSException*e){ |
[treeControllersetValue:nilforKeyPath:@"selection.predicate"]; |
} |
@finally{ |
[NSAppendSheet:sheet]; |
} |
} |
} |
ThrowingExceptions
Usingitastheargumentofa@throwcompilerdirective
Sendingita
messageraise
Thefollowingexampleshowshowyouthrowanexceptionusingthe
@throwdirective(the
raisealternative
iscommentedout):
NSException*myException=[NSException |
exceptionWithName:@"FileNotFoundException" |
reason:@"FileNotFoundonSystem" |
userInfo:nil]; |
@throwmyException; |
//[myExceptionraise];/*equivalenttoabovedirective*/ |
@try{ |
NSException*e=[NSException |
exceptionWithName:@"FileNotFoundException" |
reason:@"FileNotFoundonSystem" |
userInfo:nil]; |
@throwe; |
} |
@catch(NSException*e){ |
@throw;//rethrowseimplicitly |
} |
@try{ |
//... |
if(someError){ |
NSException*theException=[NSExceptionexceptionWithName:MyAppExceptionreason:@"Someerrorjustoccurred!"userInfo:nil]; |
@throwtheException; |
} |
} |
@catch(NSException*exception){ |
if([[exceptionname]isEqualToString:MyAppException]){ |
NSRunAlertPanel(@"ErrorPanel",@"%@",@"OK",nil,nil, |
localException); |
} |
@throw;//rethrowtheexception |
} |
@finally{ |
[selfcleanUp]; |
} |
flowwithnestedexceptionhandlers—usingdirectives
链式编程思想/链式编程?
链式编程在我们iOS中并不陌生的,比如OC中的Masonry和Swift中的SnapKit第三方就是利用的链式编程,链式编程就是把多个操作多行代码通过操作符号(通常是点.)连成一句执行的代码。来降低代码的重复度,使起看起来更易读。
对ReactiveNative,reactiveCocoa了解?
MVC,MVVM具体的实现?
IM通信机制实现。
Runtime>项目在runtime的时候进行了那些操作。
GCD简介
//01:队列的唯一标识,采用反域名形式
//02:队列的属性类型,也就是标识这个队列是串行队列还是并行队列
//(1)自己创建的串行队列中添加异步任务是在子线程中完成任务;
//(2)自己创建的串行队列中添加同步任务是在主线程中完成任务;
//总结:同步任务:不管在哪一个队列中都是主线程中执行,但是不能将其添加到系统自带的串行队列中;
//异步任务:在自己创建的串行队列中,在子线程中执行,如果是系统创建的队列在主线程中执行;
相关文章推荐
- SAP ABAP(增强技术) BADI自己的一些了解,以及用法
- 了解场景以及解决方案来学习技术
- SDK技术的发展进程以及了解概况
- 全面了解TLC NAND技术以及市场现状
- 详解加密技术概念、加密方法以及应用(3)
- 最新数字绘图技术:实时墨迹模拟 — 墨迹渗透
- 搜索引擎设计实用教程(1)-以百度为例 之一:查询处理以及分词技术
- 了解RAID技术[转帖]
- [摘录]该怎样规划自己的技术发展方向以及人生发展的总体思路
- [技术]window.open的使用方法以及参数说明
- 详解加密技术概念、加密方法以及应用(1)
- C# 2.0 杂项技术,以及C#语言的未来发展
- C# 2.0 杂项技术,以及C#语言的未来发展(选择自 shoutor 的 Blog )
- 聚簇索引与非聚簇索引的区别以及SQL Server查询优化技术
- C# 2.0 杂项技术,以及C#语言的未来发展
- SYN攻击原理以及防范技术
- Ajax基础必读:AJAX中的一些关键技术(解析xml的封装类,以及操纵DOM对象)
- 聚簇索引与非聚簇索引的区别以及SQL Server查询优化技术