iOS Reviews Questions
References:
iOSInterviewQuestions
Why Apple suggest using NS_ENUM
or NS_OPTIONS
to declare an enum?
In Objective-C, we can declare an enum with three ways.
The differences between them:
-
First, we can find that the
DogType
and theBirdType
specify an underlying typeNSInteger
for themselves. But theCatType
doesn’t specify any special type. In this situation, the compiler will decide the base type whatever he like. (maybe: char, short, or even a 24 bit integer) -
Second, the compiler specifically recognizes the NS_ENUM macro, so it knows that you have an enum with values that shouldn’t be combined like flags, the debugger knows what’s going on, and the enum can be translated to Swift automatically.
If we use them in Swift, what will happen?
-
When declaring an
CatType
enum , we will find that theCatType
isn’t an enum type in Swift. It’s transformed to an alias ofUInt32
.
The casesCatTypeOne
andCatTypeTwo
are actually two UInt32 numbers. -
The enum
DogType
is much better, Swift compiler would transform it to an true enum type.
But if we want to use its case, you wil find there are some questions when writing. We can’t define a case likeDogType.one
. The compiler didn’t help us transform these OC enum cases to Swift form. You can only use them like using an OC form enum.
Of course you can write an extension for it, then you can use it as using a real Swift enum. (var dog: DogType = .one
) You can use the initialization methodlet dog4 = DogType.init(4)
to declare an new case.
-
If you use
NS_ENUM
to declare an enum in OC, you need to do nothing when using in Swift. The Swift compiler would completely transform it to a Swift enum.
So make sure you use NS_ENUM
to declare your enums in OC, then can freely use them in OC or Swift files without any transformations.
Why suggest using instancetype
to replace id
as the return type of init methods?
In the early, we all know the return type of constructors and factory methods was id
. Why use id
instead of certain type? This is because OC is an Object-Oriented language. A sub class will inherit the constructors of its super class. If we initialize an instance by the sub class, the actual return value of the constructor is a sub class instance, so we can’t use an certain type to define the return value type, we need a general type can references all object types.
But there are some questions we can’t resolve, the first is we can invoke a method the class doesn’t have and the compiler warns nothing, the app will crash when running to this code.
The class TestModel
doesn’t have a method or property named length
. The reason we can invoke this method is the instance is an id type and the id
type can invoke all methods of all classes in the project.
Afterwards, Apple provides a new type instancetype
to replace the id
type. The instancetype
is not a certain type or a general type like id
, it’s just a compiler flag. It can only be used as the return value type of functions. We invoke the constructor again after changing the return value type to instancetype
, the return value won’t be an id
type, it becomes the certain type as same as the class invoked. Then the compiler can display correct code hints and display warning message when you invoke error methods.
This is why we should use instancetype
, not id
.
In which situation should we use the weak
keyword? What are the differences compared with the assign
?
In which situation should we use the weak
keyword?
- In
ARC
, we will mark one side withweak
keyword when there are possibly any cycle reference in some particular scenes. (eg:delegate
) - In some particular scenes, the object will be referenced by
"itself"
, we don’t need to reference it twice. For example, we can declareIBOutlet
controls properties withweak
. This is because there is a private_topLevelObjectsToKeepAliveFromStoryboard
array in theViewController
created by storyboard(not xib), the array would references all top level objects.
What are the differences compared with assign
?
- Firstly, the modifier
assign
can declare non-object types, but theweak
must be used to declare object types. - When we assign a value to a property declared with the
weak
, the old object referenced by the property won’t perform therelease
action and the new object assigned to the property won’t perform theretain
action. In this case, theassign
andweak
have the same behaviors. The difference between them is that the weak property will benil
when the object referenced by it was released. The modifierassign
is used to declare scaler types (eg: CGFloat, Int, Double, Bool), the setting method of it just perform the easiest assigning action.
How to use the keyword copy
?
Usages:
NSString, NSArray, NSDictionary
usually use the keywordcopy
, because they have the corresponding mutable types,NSMutableString, NSMutableArray, NSMutableDictionary
.- The
block
also often use the keywordcopy
. Concrete Reason: Objects Use Properties to Keep Track of Blocks
Using copy
to decorate a block is a legacy from MRC. In MRC, the block created in function is in the stack area, we need to copy it to the heap area. But this isn’t something you need to worry about when using ARC, it will happen automatically.
In ARC, the copying action will be performed automatically in these situations:
block
as functions’ return value- Assign a block to a
__strong
reference pointer. - As a parameter of a Cocoa API function that’s name contains the string
using Block
. - As the function parameters of GCD API.
Of course you can decorate a block with the modifier
strong
, it’s OK. But it’s best practice for the property attribute to show the resultant behavior.
Are there any question when you write like this @property (copy) NSMutableArray *array
?
- The first, you use the modifier
copy
to decorate a mutable type, when you assign a value to the property array, it will copy the mutable array and transform it to an immutable array in the setter function. At the moment, if you invoke a mutable array’s function (eg: insert) to the property array, you will get a crash because the function cannot be found. - The second, Using
atomic
would heavily depress the App’s performance. There isn’t an modifier namedatomic
, so if you don’t mark one property withnonatomic
, the property will beatomic
.
Why do not suggest declaring an atomic property?
We know the purpose of using the modifier atomic
is for multithread safe, the compiler will generate some additional code to keep thread safe, it’ll bring some performance troubles. Unfortunately, just using the atomic
can’t achieve ours aim to implement thread safe, we need a more deeper locking mechanism.
How to make our custom classes can use the modifier copy
? How to overwrite the setter method of the copying property?
If you want to define a yourself class can be copy, your class needs to abide by the NSCopying
protocol. If your class has two forms, mutable and immutable, you must abide by two protocols NSCopying
and NSMutableCopying
at the same time.
Detail steps:
- Declare the class abiding by the protocol.
- Implement the protocol method
-(id)copyWithZone:(NSZone *)zone
.
What is the essence of the modifier @property
? How to generate ivar
,getter
and setter
and insert them to classes?
@property = ivar + getter + setter
Property
is a feature of Objective-C, its mainly purpose is to encapsulating the data in the class. Objective-C usually uses various instance variables to store data. And then using the accessing method to set or get data from instance variables. This feature was introduced in Objective-C 2.0. In formal Objective-C coding specification, the getter and setter method have strict naming conventions, so the compiler can help us automatically generate the accessing functions.