您的位置:首页 > 职场人生

技术了解以及渗透

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语言的操作系统;它使语言文字工作。

这个文件看
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程序时。所有的这些功能是记录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
display
method
isassociatedwith
display
’saddress,andsoon.

Figure
3-1MessagingFramework







Whenamessageissenttoanobject,themessagingfunctionfollowstheobject’s
isa
pointer
totheclassstructurewhereitlooksupthemethodselectorinthedispatchtable.Ifitcan’tfindtheselectorthere,
objc_msgSend
followsthepointerto
thesuperclassandtriestofindtheselectorinitsdispatchtable.Successivefailurescause
objc_msgSend
toclimbtheclasshierarchyuntilitreachesthe
NSObject
class.
Onceitlocatestheselector,thefunctioncallsthemethodenteredinthetableandpassesitthereceivingobject’sdatastructure.

Thisisthewaythatmethodimplementationsarechosenatruntime—or,inthejargonofobject-orientedprogramming,thatmethodsaredynamicallyboundtomessages.
加速消息传递过程中,运行时系统缓存使用选择器和地址的方法。有一个单独的缓存中为每个类,它可以包含继承的方法以及方法的选择器中定义的类。之前搜索调度表,收到的消息传递程序首先检查缓存对象的类(在理论,一种方法是使用一次可能会再次使用)。如果选择器的方法是在缓存中,消息传递是仅略低于一个函数调用。一旦一个程序被运行足够长的时间来“热身”其缓存,几乎所有它发送的消息找到缓存的方法。缓存生长在程序运行时动态地适应新的消息。


UsingHiddenArguments

When
objc_msgSend
finds
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(seeDeclared
PropertiesinTheObjective-CProgrammingLanguage)includesthe
@dynamic
directive:

@dynamicpropertyName;

Youcanimplementthemethods
resolveInstanceMethod:
and
resolveClassMethod:
to
dynamicallyprovideanimplementationforagivenselectorforaninstanceandclassmethodrespectively.

AnObjective-CmethodissimplyaCfunctionthattakeatleasttwoarguments—
self
and
_cmd
.
Youcanaddafunctiontoaclassasamethodusingthefunction
class_addMethod
.
Therefore,giventhefollowingfunction:

voiddynamicMethodIMP(idself,SEL_cmd){

//implementation....

}

youcandynamicallyaddittoaclassasamethod(called
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
super
keyword)
aresentusing
objc_msgSendSuper
;othermessagesaresentusing
objc_msgSend
.
Methodsthathavedatastructuresasreturnvaluesaresentusing
objc_msgSendSuper_stret
and
objc_msgSend_stret
.

8ARC?

ARC的工作原理是编译时添加代码,以确保对象在必要的时候生存,并不是你记得的什么时候release,return和autorelease,ARC对你的对象的生存期的要求和自动插入适当的内存管理当你在编译的时候,编译器也会为你生成合适的dealloc方法,

Acompleteandcorrectimplementationofa
Person
classmightlooklikethis:

@interfacePerson:NSObject

@propertyNSString*firstName;

@propertyNSString*lastName;

@propertyNSNumber*yearOfBirth;

@propertyPerson*spouse;

@end


@implementationPerson

@end

(Objectpropertiesare
strong
bydefault;the
strong
attribute
isdescribedinARC
IntroducesNewLifetimeQualifiers.)

UsingARC,youcouldimplementacontrivedmethodlikethis:

-(void)contrived{

Person*aPerson=[[Personalloc]init];

[aPersonsetFirstName:@"William"];

[aPersonsetLastName:@"Dudney"];

[aPersonsetYearOfBirth:[[NSNumberalloc]initWithInteger:2011]];

NSLog(@"aPerson:%@",aPerson);

}

ARCtakescareofmemorymanagementsothatneitherthe
Person
northe
NSNumber
objects
areleaked.

Youcouldalsosafelyimplementa
takeLastNameFrom:
methodof
Person
like
this:

-(void)takeLastNameFrom:(Person*)person{

NSString*oldLastname=[selflastName];

[selfsetLastName:[personlastName]];

NSLog(@"Lastnamechangedfrom%@to%@",oldLastname,[selflastName]);

}

ARCensuresthat
oldLastName
isnotdeallocatedbeforethe
NSLog
statement.
ARC的一些新的规则:

工作时,arc对一些新的规章制度,不使用其他编译模式。该规则旨在提供一个完全可靠的内存管理模型;在某些情况下,他们只是执行的最佳实践,在一些可以简化代码或是明显的你不必处理内存管理的推论。如果你违反了这些规则,你会得到一个即时编译时错误,不是一个微妙的错误,可能会在运行时明显。

Youcannotexplicitlyinvoke
dealloc
,orimplementorinvoke
retain
,
release
,
retainCount
,
or
autorelease
.
Theprohibitionextendstousing
@selector(retain)
,
@selector(release)
,
andsoon.
Youmayimplementa
dealloc
methodifyouneedtomanageresourcesotherthanreleasing
instancevariables.Youdonothaveto(indeedyoucannot)releaseinstancevariables,butyoumayneedtoinvoke
[systemClassInstancesetDelegate:nil]
on
systemclassesandothercodethatisn’tcompiledusingARC.
Custom
dealloc
methodsinARCdonotrequireacallto
[super
dealloc]
(itactuallyresultsinacompilererror).Thechainingtosuperisautomatedandenforcedbythecompiler.
Youcanstilluse
CFRetain
,
CFRelease
,
andotherrelatedfunctionswithCoreFoundation-styleobjects(seeManaging
Toll-FreeBridging).

Youcannotuse
NSAllocateObject
or
NSDeallocateObject
.
Youcreateobjectsusing
alloc
;
theruntimetakescareofdeallocatingobjects.

YoucannotuseobjectpointersinCstructures.
Ratherthanusinga
struct
,youcancreateanObjective-Cclasstomanagethedata
instead.

Thereisnocasualcastingbetween
id
and
void*
.
Youmustusespecialcaststhattellthecompileraboutobjectlifetime.YouneedtodothistocastbetweenObjective-CobjectsandCoreFoundationtypesthatyoupassasfunctionarguments.
Formoredetails,seeManaging
Toll-FreeBridging.

Youcannotuse
NSAutoreleasePool
objects.
ARCprovides
@autoreleasepool
blocksinstead.Thesehaveanadvantageofbeingmore
efficientthan
NSAutoreleasePool
.

Youcannotusememoryzones.
Thereisnoneedtouse
NSZone
anymore—theyareignoredbythemodernObjective-C
runtimeanyway.


PropertyAttributes

Thekeywords
weak
and
strong
areintroducedasnew
declaredpropertyattributes,asshowninthefollowingexamples.

//Thefollowingdeclarationisasynonymfor:@property(retain)MyClass*myObject;

@property(strong)MyClass*myObject;


//Thefollowingdeclarationissimilarto"@property(assign)MyClass*myObject;"

//exceptthatiftheMyClassinstanceisdeallocated,

//thepropertyvalueissettonilinsteadofremainingasadanglingpointer.

@property(weak)MyClass*myObject;

UnderARC,
strong
isthedefaultforobjecttypes.


VariableQualifiers

Youusethefollowinglifetimequalifiersforvariablesjustlikeyouwould,say,
const
.

__strong

__weak

__unsafe_unretained

__autoreleasing

__strong
isthedefault.Anobjectremains“alive”aslongasthereisastrongpointertoit.(只要有一个指向它的强指针,对象仍然是“活着的”。)

__weak
specifiesareferencethatdoesnotkeepthereferencedobjectalive.Aweakreferenceissetto
nil
when
therearenostrongreferencestotheobject.(指定不保留引用对象的引用。如果没有对对象的强引用,则弱引用将设置为零。)

__unsafe_unretained
specifiesareferencethatdoesnotkeepthereferencedobjectaliveandisnotsetto
nil
when
therearenostrongreferencestotheobject.Iftheobjectitreferencesisdeallocated,thepointerisleftdangling.指定一个引用,该引用不保留引用对象的生存状态,并且在没有对对象进行强引用时不会将其设置为零。如果引用的对象被释放,指针是摇摇欲坠。)

__autoreleasing
isusedtodenoteargumentsthatarepassedbyreference(
id
*
)andareautoreleasedonreturn.

Youshoulddecoratevariablescorrectly.Whenusingqualifiersinanobjectvariabledeclaration,thecorrectformatis:

ClassName*qualifiervariableName;

forexample:

MyClass*__weakmyWeakReference;

MyClass*__unsafe_unretainedmyUnsafeReference;

Othervariantsaretechnicallyincorrectbutare“forgiven”bythecompiler.Tounderstandtheissue,seehttp://cdecl.org/.

Takecarewhenusing
__weak
variablesonthestack.Considerthefollowingexample:

NSString*__weakstring=[[NSStringalloc]initWithFormat:@"FirstName:%@",[selffirstName]];

NSLog(@"string:%@",string);

Although
string
isusedaftertheinitialassignment,thereisnootherstrongreferencetothestringobjectatthetimeofassignment;itisthereforeimmediately
deallocated.Thelogstatementshowsthat
string
hasanullvalue.(Thecompilerprovidesawarninginthissituation.)

Youalsoneedtotakecarewithobjectspassedbyreference.Thefollowingcodewillwork:

NSError*error;

BOOLOK=[myObjectperformOperationWithError:&error];

if(!OK){

//Reporttheerror.

//...

However,theerrordeclarationisimplicitly:

NSError*__stronge;

andthemethoddeclarationwouldtypicallybe:

-(BOOL)performOperationWithError:(NSError*__autoreleasing*)error;

Thecompilerthereforerewritesthecode:

NSError*__strongerror;

NSError*__autoreleasingtmp=error;

BOOLOK=[myObjectperformOperationWithError:&tmp];

error=tmp;

if(!OK){

//Reporttheerror.

//...

Themismatchbetweenthelocalvariabledeclaration(
__strong
)andtheparameter(
__autoreleasing
)
causesthecompilertocreatethetemporaryvariable.Youcangettheoriginalpointerbydeclaringtheparameter
id__strong*
whenyoutaketheaddress
ofa
__strong
variable.Alternativelyyoucandeclarethevariableas
__autoreleasing
.


UseLifetimeQualifierstoAvoidStrongReferenceCycles

Youcanuselifetimequalifierstoavoidstrongreferencecycles.Forexample,typicallyifyouhaveagraphofobjectsarrangedinaparent-childhierarchyandparentsneedtorefertotheirchildrenandviceversa,thenyoumaketheparent-to-childrelationship
strongandthechild-to-parentrelationshipweak.Othersituationsmaybemoresubtle,particularlywhentheyinvolveblock
objects.

Inmanualreferencecountingmode,
__blockidx;
hastheeffectofnotretaining
x
.
InARCmode,
__blockidx;
defaultstoretaining
x
(just
likeallothervalues).TogetthemanualreferencecountingmodebehaviorunderARC,youcoulduse
__unsafe_unretained__blockidx;
.Asthename
__unsafe_unretained
implies,
however,havinganon-retainedvariableisdangerous(becauseitcandangle)andisthereforediscouraged.Twobetteroptionsaretoeitheruse
__weak
(if
youdon’tneedtosupportiOS4orOSXv10.6),orsetthe
__block
valueto
nil
to
breaktheretaincycle.

Thefollowingcodefragmentillustratesthisissueusingapatternthatissometimesusedinmanualreferencecounting.

MyViewController*myController=[[MyViewControlleralloc]init…];

//...

myController.completionHandler=^(NSIntegerresult){

[myControllerdismissViewControllerAnimated:YEScompletion:nil];

};

[selfpresentViewController:myControlleranimated:YEScompletion:^{

[myControllerrelease];

}];

Asdescribed,instead,youcanusea
__block
qualifierandsetthe
myController
variable
to
nil
inthecompletionhandler:

MyViewController*__blockmyController=[[MyViewControlleralloc]init…];

//...

myController.completionHandler=^(NSIntegerresult){

[myControllerdismissViewControllerAnimated:YEScompletion:nil];

myController=nil;

};

Alternatively,youcanuseatemporary
__weak
variable.Thefollowingexampleillustratesasimpleimplementation:

MyViewController*myController=[[MyViewControlleralloc]init…];

//...

MyViewController*__weakweakMyViewController=myController;

myController.completionHandler=^(NSIntegerresult){

[weakMyViewControllerdismissViewControllerAnimated:YEScompletion:nil];

};

Fornon-trivialcycles,however,youshoulduse:

MyViewController*myController=[[MyViewControlleralloc]init…];

//...

MyViewController*__weakweakMyController=myController;

myController.completionHandler=^(NSIntegerresult){

MyViewController*strongMyController=weakMyController;

if(strongMyController){

//...

[strongMyControllerdismissViewControllerAnimated:YEScompletion:nil];

//...

}

else{

//Probablynothing...

}

};

UseLifetimeQualifierstoAvoidStrongReferenceCycles


Youcanuselifetimequalifierstoavoidstrongreferencecycles.Forexample,typicallyifyouhaveagraphofobjectsarrangedinaparent-childhierarchyandparentsneedtorefertotheirchildrenandviceversa,thenyoumaketheparent-to-childrelationship
strongandthechild-to-parentrelationshipweak.Othersituationsmaybemoresubtle,particularlywhentheyinvolveblock
objects.

Inmanualreferencecountingmode,
__blockidx;
hastheeffectofnotretaining
x
.
InARCmode,
__blockidx;
defaultstoretaining
x
(just
likeallothervalues).TogetthemanualreferencecountingmodebehaviorunderARC,youcoulduse
__unsafe_unretained__blockidx;
.Asthename
__unsafe_unretained
implies,
however,havinganon-retainedvariableisdangerous(becauseitcandangle)andisthereforediscouraged.Twobetteroptionsaretoeitheruse
__weak
(if
youdon’tneedtosupportiOS4orOSXv10.6),orsetthe
__block
valueto
nil
to
breaktheretaincycle.

Thefollowingcodefragmentillustratesthisissueusingapatternthatissometimesusedinmanualreferencecounting.

MyViewController*myController=[[MyViewControlleralloc]init…];

//...

myController.completionHandler=^(NSIntegerresult){

[myControllerdismissViewControllerAnimated:YEScompletion:nil];

};

[selfpresentViewController:myControlleranimated:YEScompletion:^{

[myControllerrelease];

}];

Asdescribed,instead,youcanusea
__block
qualifierandsetthe
myController
variable
to
nil
inthecompletionhandler:

MyViewController*__blockmyController=[[MyViewControlleralloc]init…];

//...

myController.completionHandler=^(NSIntegerresult){

[myControllerdismissViewControllerAnimated:YEScompletion:nil];

myController=nil;

};

Alternatively,youcanuseatemporary
__weak
variable.Thefollowingexampleillustratesasimpleimplementation:

MyViewController*myController=[[MyViewControlleralloc]init…];

//...

MyViewController*__weakweakMyViewController=myController;

myController.completionHandler=^(NSIntegerresult){

[weakMyViewControllerdismissViewControllerAnimated:YEScompletion:nil];

};

Fornon-trivialcycles,however,youshoulduse:

MyViewController*myController=[[MyViewControlleralloc]init…];

//...

MyViewController*__weakweakMyController=myController;

myController.completionHandler=^(NSIntegerresult){

MyViewController*strongMyController=weakMyController;

if(strongMyController){

//...

[strongMyControllerdismissViewControllerAnimated:YEScompletion:nil];

//...

}

else{

//Probablynothing...

}

};

Insomecasesyoucanuse
__unsafe_unretained
iftheclassisn’t
__weak
compatible.
Thiscan,however,becomeimpracticalfornontrivialcyclesbecauseitcanbehardorimpossibletovalidatethatthe
__unsafe_unretained
pointerisstill
validandstillpointstothesameobjectinquestion.


ManagingToll-FreeBridging

InmanyCocoaapplications,youneedtouseCoreFoundation-styleobjects,whetherfromtheCoreFoundationframeworkitself(suchas
CFArrayRef
or
CFMutableDictionaryRef
)
orfromframeworksthatadoptCoreFoundationconventionssuchasCoreGraphics(youmightusetypeslike
CGColorSpaceRef
and
CGGradientRef
).

ThecompilerdoesnotautomaticallymanagethelifetimesofCoreFoundationobjects;youmustcall
CFRetain
and
CFRelease
(or
thecorrespondingtype-specificvariants)asdictatedbytheCoreFoundationmemorymanagementrules(seeMemory
ManagementProgrammingGuideforCoreFoundation).

IfyoucastbetweenObjective-CandCoreFoundation-styleobjects,youneedtotellthecompilerabouttheownershipsemanticsoftheobjectusingeitheracast(definedin
objc/runtime.h
)
oraCoreFoundation-stylemacro(definedin
NSObject.h
):

__bridge
transfersapointerbetweenObjective-CandCoreFoundationwithnotransferofownership.

__bridge_retained
or
CFBridgingRetain
castsanObjective-C
pointertoaCoreFoundationpointerandalsotransfersownershiptoyou.

Youareresponsibleforcalling
CFRelease
orarelatedfunctiontorelinquishownershipoftheobject.

__bridge_transfer
or
CFBridgingRelease
movesanon-Objective-C
pointertoObjective-CandalsotransfersownershiptoARC.

ARCisresponsibleforrelinquishingownershipoftheobject.

Forexample,ifyouhadcodelikethis:

-(void)logFirstNameOfPerson:(ABRecordRef)person{


NSString*name=(NSString*)ABRecordCopyValue(person,kABPersonFirstNameProperty);

NSLog(@"Person'sfirstname:%@",name);

[namerelease];

}

youcouldreplaceitwith:

-(void)logFirstNameOfPerson:(ABRecordRef)person{


NSString*name=(NSString*)CFBridgingRelease(ABRecordCopyValue(person,kABPersonFirstNameProperty));

NSLog(@"Person'sfirstname:%@",name);

}

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
runloopmodes

Mode
Name
Description
Default
NSDefaultRunLoopMode
(Cocoa)

kCFRunLoopDefaultMode
(Core
Foundation)
Thedefaultmodeistheoneusedformostoperations.Mostofthetime,youshouldusethismodetostartyourrunloopandconfigureyourinputsources.
Connection
NSConnectionReplyMode
(Cocoa)
Cocoausesthismodeinconjunctionwith
NSConnection
objects
tomonitorreplies.Youshouldrarelyneedtousethismodeyourself.
Modal
NSModalPanelRunLoopMode
(Cocoa)
Cocoausesthismodetoidentifyeventsintendedformodalpanels.
Eventtracking
NSEventTrackingRunLoopMode
(Cocoa)
Cocoausesthismodetorestrictincomingeventsduringmouse-draggingloopsandothersortsofuserinterfacetrackingloops.
Commonmodes
NSRunLoopCommonModes
(Cocoa)

kCFRunLoopCommonModes
(Core
Foundation)
Thisisaconfigurablegroupofcommonlyusedmodes.Associatinganinputsourcewiththismodealsoassociatesitwitheachofthemodesinthegroup.ForCocoaapplications,thissetincludesthedefault,modal,andeventtrackingmodesbydefault.CoreFoundation
includesjustthedefaultmodeinitially.Youcanaddcustommodestothesetusingthe
CFRunLoopAddCommonMode
function
Table3-2Performingselectorsonotherthreads

Methods
Description
performSelectorOnMainThread:withObject:waitUntilDone:


performSelectorOnMainThread:withObject:waitUntilDone:modes:

Performsthespecifiedselectorontheapplication’smainthreadduringthatthread’snextrunloopcycle.Thesemethodsgiveyoutheoptionofblockingthecurrentthreaduntiltheselectorisperformed.
performSelector:onThread:withObject:waitUntilDone:


performSelector:onThread:withObject:waitUntilDone:modes:

Performsthespecifiedselectoronanythreadforwhichyouhavean
NSThread
object.
Thesemethodsgiveyoutheoptionofblockingthecurrentthreaduntiltheselectorisperformed.
performSelector:withObject:afterDelay:


performSelector:withObject:afterDelay:inModes:

Performsthespecifiedselectoronthecurrentthreadduringthenextrunloopcycleandafteranoptionaldelayperiod.Becauseitwaitsuntilthenextrunloopcycletoperformtheselector,thesemethodsprovideanautomaticminidelayfromthecurrently
executingcode.Multiplequeuedselectorsareperformedoneafteranotherintheordertheywerequeued.
cancelPreviousPerformRequestsWithTarget:


cancelPreviousPerformRequestsWithTarget:selector:object:

Letsyoucancelamessagesenttothecurrentthreadusingthe
performSelector:withObject:afterDelay:
or
performSelector:withObject:afterDelay:inModes:
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);

}

Figure3-2Operating
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];

Table4-1Locktypes

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
pthread
man
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

Anoperationobjectisaninstanceofthe
NSOperation
class(intheFoundationframework)thatyou
usetoencapsulateworkyouwantyourapplicationtoperform.The
NSOperation
classitselfisanabstractbaseclassthatmustbesubclassedinorderto
doanyusefulwork.Despitebeingabstract,thisclassdoesprovideasignificantamountofinfrastructuretominimizetheamountofworkyouhavetodoinyourownsubclasses.Inaddition,theFoundationframeworkprovidestwoconcretesubclassesthatyou
canuseas-iswithyourexistingcode.Table2-1liststheseclasses,alongwithasummaryofhowyouuseeachone.

Table2-1OperationclassesoftheFoundationframework

Class
Description
NSInvocationOperation

Aclassyouuseas-istocreateanoperationobjectbasedonanobjectandselectorfromyourapplication.
Youcanusethisclassincaseswhereyouhaveanexistingmethodthatalreadyperformstheneededtask.Becauseitdoesnotrequiresubclassing,youcanalsousethisclasstocreateoperationobjectsinamoredynamicfashion.

Forinformationabouthowtousethisclass,seeCreating
anNSInvocationOperationObject.
NSBlockOperation

Aclassyouuseas-istoexecuteoneormoreblockobjectsconcurrently.Becauseitcanexecute
morethanoneblock,ablockoperationobjectoperatesusingagroupsemantic;onlywhenalloftheassociatedblockshavefinishedexecutingistheoperationitselfconsideredfinished.

Forinformationabouthowtousethisclass,seeCreating
anNSBlockOperationObject.ThisclassisavailableinOSXv10.6andlater.Formoreinformationaboutblocks,seeBlocks
ProgrammingTopics.
NSOperation

Thebaseclassfordefiningcustomoperationobjects.Subclassing
NSOperation
givesyoucompletecontrolovertheimplementationofyourownoperations,including
theabilitytoalterthedefaultwayinwhichyouroperationexecutesandreportsitsstatus.

Forinformationabouthowtodefinecustomoperationobjects,seeDefining
aCustomOperationObject.

Listing2-1Creatingan
NSInvocationOperation
object

@implementationMyCustomClass

-(NSOperation*)taskWithData:(id)data{

NSInvocationOperation*theOp=[[NSInvocationOperationalloc]initWithTarget:self

selector:@selector(myTaskMethod:)object:data];


returntheOp;

}


//Thisisthemethodthatdoestheactualworkofthetask.

-(void)myTaskMethod:(id)data{

//Performthetask.

}

@end

Listing2-2Creatingan
NSBlockOperation
object

NSBlockOperation*theOp=[NSBlockOperationblockOperationWithBlock:^{

NSLog(@"Beginningoperation.\n");

//Dosomework.

}];


PerformingtheMainTask

Ataminimum,everyoperationobjectshouldimplementatleastthefollowingmethods:

Acustominitializationmethod

main


Youneedacustominitializationmethodtoputyouroperationobjectintoaknownstateandacustom
main
methodtoperformyourtask.Youcanimplementadditional
methodsasneeded,ofcourse,suchasthefollowing:

Custommethodsthatyouplantocallfromtheimplementationofyour
main
method

Accessormethodsforsettingdatavaluesandaccessingtheresultsoftheoperation

Methodsofthe
NSCoding
protocol
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

Tocreateaqueue,youallocateitinyourapplicationasyouwouldanyotherobject:

NSOperationQueue*aQueue=[[NSOperationQueuealloc]init];

[aQueueaddOperation:anOp];//Addasingleoperation

[aQueueaddOperations:anArrayOfOpswaitUntilFinished:NO];//Addmultipleoperations

[aQueueaddOperationWithBlock:^{

/*Dosomething.*/

}];

Notifications

An
NSNotification
object(referredtoasanotification)containsaname,anobject,andanoptionaldictionary.Thenameisatagidentifyingthenotification.
Theobjectisanyobjectthattheposterofthenotificationwantstosendtoobserversofthatnotification—typicallytheobjectthatpostedthenotificationitself.Thedictionarymaycontainadditionalinformationabouttheevent.

Cocoaincludestwotypesofnotificationcenters:

The
NSNotificationCenter
classmanagesnotificationswithinasingleprocess.

The
NSDistributedNotificationCenter
classmanagesnotificationsacrossmultipleprocessesonasinglecomputer.


Model-View-Controller



Exceptions

an
NSException
objectarethefollowing:

A
name

ashortstringthatisusedtouniquelyidentifytheexception.Thenameisrequired.

A
reason

alongerstringthatcontainsa“human-readable”reasonfortheexception.Thereasonisrequired.

Anoptionaldictionary(
userInfo
)
usedtosupplyapplication-specificdatatotheexceptionhandler.Forexample,ifthereturnvalueofamethodcausesanexceptiontoberaised,youcouldpassthereturnvaluetotheexceptionhandlerthrough
userInfo
.

The
@try
,
@catch
,and
@finally
directives
constituteacontrolstructure.Thesectionofcodebetweenthebracesin
@try
istheexceptionhandlingdomain;thecodeina
@catch
block
isalocalexceptionhandler;the
@finally
blockofcodeisacommon“housekeeping”section.InFigure
1,thenormalflowofprogramexecutionismarkedbythegrayarrow;thecodewithinthelocalexceptionhandlerisexecutedonlyifanexceptionisthrown—eitherbythelocalexceptionhandlingdomainoronefurtherdownthecallsequence.Thethrowing
(orraising)ofanexceptioncausesprogramcontroltojumptothefirstexecutablelineofthelocalexceptionhandler.Aftertheexceptionishandled,control“fallsthrough”tothe
@finally
block;
ifnoexceptionisthrown,controljumpsfromthe
@try
blocktothe
@finally
block.
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
@throw
compilerdirective

Sendingita
raise
message

Thefollowingexampleshowshowyouthrowanexceptionusingthe
@throw
directive(the
raise
alternative
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

}

Listing1Throwingandre-throwinganexception

@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];

}

Figure1Control
flowwithnestedexceptionhandlers—usingdirectives



链式编程思想/链式编程?

链式编程在我们iOS中并不陌生的,比如OC中的Masonry和Swift中的SnapKit第三方就是利用的链式编程,链式编程就是把多个操作多行代码通过操作符号(通常是点.)连成一句执行的代码。来降低代码的重复度,使起看起来更易读。

对ReactiveNative,reactiveCocoa了解?

MVC,MVVM具体的实现?

IM通信机制实现。

Runtime>项目在runtime的时候进行了那些操作。

GCD简介

//01:队列的唯一标识,采用反域名形式

//02:队列的属性类型,也就是标识这个队列是串行队列还是并行队列

//(1)自己创建的串行队列中添加异步任务是在子线程中完成任务;

//(2)自己创建的串行队列中添加同步任务是在主线程中完成任务;

//总结:同步任务:不管在哪一个队列中都是主线程中执行,但是不能将其添加到系统自带的串行队列中;
//异步任务:在自己创建的串行队列中,在子线程中执行,如果是系统创建的队列在主线程中执行;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  iOS面试