Sources include, but not limited to:
- https://izeeshan.wordpress.com/2015/03/31/interview-stuff/
- https://github.com/9magnets/iOS-Developer-and-Designer-Interview-Questions
- https://www.quora.com/What-do-startups-look-for-in-a-candidate-during-an-iOS-technical-interview-What-do-they-want-to-hear
- https://www.linkedin.com/pulse/ios-interview-questions-senior-developers-alex-bush
- https://www.raywenderlich.com/110982/swift-interview-questions-answers
The main difference is; Structs are passed by value and classes are passed by reference.
No, Objective C does not have GC, It does not scan heap for unused objects, no whole app pause, no deterministic release of any NS Object. Objective C used Manual Reference Counting until iOS 5 in terms of ‘retain’, ‘release’, and Automatic Reference Count in terms of ‘strong’, ‘weak’.
The only difference between weak and assign is that if the object a weak property points to is deallocated, then the value of the weak pointer will be set to nil, so that you never run the risk of accessing garbage. If you use assign, that won’t happen, so if the object gets deallocated from under you and you try to access it, you will access garbage. weak does not work with primitive types like int, double. weak only works with ObjectiveC objects.
There definitely is a benefit. When you use 'id', you get essentially no type checking at all. With instancetype, the compiler and IDE know what type of thing is being returned, and can check your code better and autocomplete better. Only use it where it makes sense of course (i.e. a method that is returning an instance of that class); id is still useful.
#import: Improved version of include, brings entire header file into current file #include: With objective C, there is performance hit with #include, compiler must open up each header file to notice the include guard. @class: A forward declaration compiler directive, It tells the compiler that class exists, does not know anything about class. It minimizes the amount of code seen by the compiler or linker.
http://nshipster.com/at-compiler-directives/
It’s a memory debugging aid. Specifically, when you set NSZombieEnabled then whenever an object reaches retain count 0, rather than begin deallocated it morphs itself into an NSZombie instance. Whenever such a zombie receives a message, it logs a warning rather than crashing or behaving in an unpredictable way.
- Not Running: The app has not been launched or it has been terminated.
- Inactive: The app is in the foreground but not receiving events, Ex. User has locked the device with the app active.
- Active: The normal state of “In Use” for an app.
- Background: The app is no longer on-screen, but still executing the code.
- Suspended: The app is still resident in memory but is not executing code.
Frame: A view’s frame (CGRect) is the position of its rectangle in the superview’s coordinate system. By default it starts at the top left. Bounds: A view’s bounds (CGRect) expresses a view rectangle in its own coordinate system. Center: A center is a CGPoint expressed in terms of the superview’s coordinate system and it determines the position of the exact center point of the view.
Blocks are created on the stack Blocks can be copied to the heap Blocks have their own private const copies of stack variables (and pointers) Mutable stack variables and pointers must be declared with the __block keyword Blocks, Operations and Retain Cycles – http://conradstoll.com/blog/2013/1/19/blocks-operations-and-retain-cycles.html Docs: http://albertodebortoli.github.io/blog/2013/04/21/objective-c-blocks-under-the-hood/ docs: http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/Blocks/Articles/00_Introduction.html http://ios-blog.co.uk/tutorials/programming-with-blocks-an-overview/
ARC / MRC (manual) reference counting. Know strong, weak and assign.
singletons should be avoided and used only for objects that need to be shared throughout your application for same reason. It should be used carefully, instantiated lazily, if it’s possible, and passed into other objects as a dependency using Inversion of Control and Dependency Injection principles.Red flag: is when the interviewee talks about global variables and stores.
Both are ways to have relationships between objects. Delegation is a one to one relationship where one object implements a delegate protocol and another uses it and sends messages to assuming that those methods are implemented since the receiver promised to comply to the protocol. KVO is many-to-many relationship where one object could broadcast a message and one or multiple other objects can listen to it and react.
A senior developer should at least be able to tell you when it is appropriate to use NSUserDefaults
, Core Data
, and disk file storage. Core Data
is what you’re expecting them to explain you the most. Other possible options are Realm
and similar third party (non-Apple) solutions but make sure they know why they would want to use them instead of Core Data
.With Core Data
they should be able to explain how it works and how it’s different from SQLite
(i.e. it’s an object graph rather than a relational database, etc.).
Interviewee should be able to explain how to do not just basic networking but more advanced things like HTTP headers and token handling. But in general look for developers who use either AFNetworking
or Alamofire
or similar.
NSCoding, JSON, pre-compiled sqlite. A good answer would be clear understanding that in general there are two types of data serialization: JSON to domain model, and domain model to persistence. Utilization of pods like Mantle or ObjectMapper or a similar library/pod is expected.
Expected answer: at least MVVM. This is the holy grail that saves iOS developers from Massive View Controllers. Senior developer should be able to explain you what MVVM is, why it’s better than MVC, and should be able to tell you what other patterns he/she uses along with MVVM (Inversion of Control, Dependency Injection, etc.).Red flags: if interviewee tells you that he uses only MVC because Apple said so and he/she never tried MVVM than that person is definitely not a senior iOS developer.
Autolayout is one of the technologies on iOS that helps us build scalable UI that can be used on many devices of different shape and size.
Expected answer: answers to this questions may vary from NSOperations and GCD to Promises and RAC From a senior developer though we expect a more higher and broader level of tools they use such as ReactiveCocoa and PromiseKit.
CocoaPods and/or Carthage. Red flags: if the say that they don’t use any dependency manager and just copy files to the project folder. Also a red flag if the use git submodules (it leads to project configuration issues and inconsistencies between local setups for different developers on the team).
explain how he/she would use breakpoints and logs to get the runtime data but from a senior developer you should expect to hear things about Instruments and Crash Logs.
Code reviews is one of the most effective development methodologies. It helps understand the problem better, share knowledge, share techniques, catch bugs, share ownership of the codebase, etc
There is only one right answer here: either they do it or they wish they would. In general iOS community isn’t as big on testing as say Ruby community. Partially it is due to inherited lack of testing culture and partially due to lack of good tools for testing but things seems to be improving on that front.
for x in (1…4) {
print (x);
}
(1…5).forEach { x in
print(x);
}
Swift implements two range operators, the closed operator and the half-open operator. The first includes all the values in a range. For example, the following includes all the integers from 0 to 4: 0...4 The half open operator doesn’t include the last element. The following produces the same 0 to 4 result: 0..<5
struct Tutorial {
var difficulty: Int = 1
}
var tutorial1 = Tutorial()
var tutorial2 = tutorial1
tutorial2.difficulty = 2
What’s the value of tutorial1.difficulty and tutorial2.difficulty? Would this be any different if Tutorial was a class? Why?
tutorial1 = 1
tutorial2 = 2
Structures in Swift are value types, and they are copied by value rather than reference. The following line creates a copy of tutorial1 and assigns it to tutorial2:
var tutorial2 = tutorial1
From this line on, any change to tutorial2 is not reflected in tutorial1.
If Tutorial were a class, both tutorial1.difficulty and tutorial2.difficulty would be 2. Classes in Swift are reference types. Any change to a property of tutorial1 would be reflected into tutorial2 and vice versa.
view1 is declared with var, and view2 is declared with let. What’s the difference here, and will the last line compile
var view1 = UIView()
view1.alpha = 0.5
let view2 = UIView()
view2.alpha = 0.5 // Will this line compile?
view1 is a variable and can be re-assigned to a new instance of UIView. With let you can assign a value only once, so the following code doesn’t compile:
view2 = view1 // Error: view2 is immutable
This code sorts an array of names alphabetically and looks complicated. Simplify it and the closure as much as you can.
let animals = ["fish", "cat", "chicken", "dog"]
let sortedAnimals = animals.sort { (one: String, two: String) -> Bool in
return one < two
}
let sortedAnimals = ["fish", "cat", "chicken", "dog”].sort { $0 < $1 }
let sortedAnimals = animals.sort(<)
var optional1: String? = nil
var optional2: String? = .None
What’s the difference between nil and .None? How do the optional1 and optional2 variables differ?
There is no difference. Optional.None (.None for short) is the correct way of initializing an optional variable lacking a value, whereas nil is just syntactic sugar for .None.
In fact, this statement outputs true:
nil == .None
// On Swift 1.x this doesn't compile. You need Optional<Int>.None
Remember that under the hood an optional is an enumeration:
enum Optional<T> {
case None
case Some(T)
}
There's an ongoing debate about whether using classes over structures is a good or bad practice. Functional programming tends to favor value types, whereas object-oriented programming prefers classes. In Swift, classes and structures differ by a number of features. You can sum up the differences as follows:
- Classes support inheritance, structures don't
- Classes are reference types, structures are value types
- At runtime, structures are more performant than classes because method invocations are statically bound, whereas method invocation for classes is dynamically resolved at runtime. That's another good reason to use structures instead of classes when possible.
Generics are used to make algorithms safely work with types. In Swift, generics can be used both in functions and data types, e.g. in classes, structures or enumerations. Generics solve the problem of code duplication. A common case is when you have a method that takes a type of parameter and you have to duplicate it just to accommodate a parameter of another type.
func areTheyEqual<T: Equatable>(x: T, _ y: T) -> Bool {
return x == y
}
areTheyEqual("ray", "ray")
areTheyEqual(1, 1)
The most common reasons to use implicitly unwrapped optionals are: 1: When a property that is not nil by nature cannot be initialized at instantiation time. A typical example is an Interface Builder outlet, which always initializes after its owner has been initialized. In this specific case -- assuming it's properly configured in Interface Builder -- the outlet is guaranteed to be non-nil before it's used. 2: To solve the strong reference cycle problem, which is when two instances refer to each other and require a non-nil reference to the other instance. In such a case, one side of the reference can be marked unowned, while the other uses an implicitly unwrapped optional. Don't use implicitly unwrapped optionals unless you must. Using them improperly increases the chance of runtime crashes. In some cases, a crash might be the intended behavior, but there are better ways to achieve the same result, for example, by using fatalError().
Hint: There are at least seven ways.
forced unwrapping ! operator -- unsafe implicitly unwrapped variable declaration -- unsafe in many cases optional binding -- safe optional chaining -- safe nil coalescing operator -- safe new Swift 2.0 guard statement -- safe new Swift 2.0 optional pattern -- safe (suggested by @Kametrixom)
guard let x = x if let x = x if let x = x as? x!
Swift is a hybrid language that supports both paradigms. It implements the three fundamental principles of OOP: Encapsulation Inheritance Polymorphism As for Swift being a functional language, there are different but equivalent ways to define it.
const int number = 0;
Here is the Swift counterpart:
let number = 0
Is there any difference between them? If yes, can you explain how they differ?
A const is a variable initialized with a compile time value or an expression resolved at compilation time. An immutable created via let is a constant determined at runtime, and it can be initialized with the result being either a static or dynamic expression. Notice that its value can only be assigned once.
Here's an example for a structure:
struct Sun {
static func illuminate() {}
}
For classes, it's possible to use either the static or the class modifier. They achieve the same goal, but in reality they're different. Can you explain how they differ? static makes a property or a function static and not overrideable When applied to classes, static becomes an alias for class final.
NO. An extension can be used to add new behavior to an existing type, but not to alter the type itself or its interface. If you add a stored property, you'd need extra memory to store the new value. An extension cannot manage such a task.
Closures are reference types. If a closure is assigned to a variable and the variable is copied into another variable, a reference to the same closure and its capture list is also copied.
Can you describe a situation where you might get a circular reference in Swift, and how you'd solve it?
A circular reference happens when two instances hold a strong reference to each other, causing a memory leak because none of two instances will ever be deallocated. The reason is that an instance cannot be deallocated as long as there's a strong reference to it, but each instance keeps the other alive because of its strong reference. You'd solve the problem by breaking the strong circular reference by replacing one of the strong references with a weak or an unowned reference.
var array1 = [1, 2, 3, 4, 5]
var array2 = array1
array2.append(6)
var len = array1.count
What’s the value of the len variable, and why?
- swift arrays are value types (implemented as structs) and not reference types (i.e. classes)
structs (incl. arrays and dictionaries) enumerations basic data types (boolean, integer, float, etc.)
Atomic and non-atomic refers to whether the setters/getters for a property will atomically read and write values to the property. When the atomic keyword is used on a property, any access to it will be “synchronized”. Therefore a call to the getter will be guaranteed to return a valid value, however this does come with a small performance penalty. Hence in some situations nonatomic is used to provide faster access to a property, but there is a chance of a race condition causing the property to be nil under rare circumstances (when a value is being set from another thread and the old value was released from memory but the new value hasn’t yet been fully assigned to the location in memory for the property).
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
The reuseIdentifier is used to indicate that a cell can be re-used in a UITableView
UITableView will maintain an internal cache of UITableViewCell’s with the reuseIdentifier and allow them to be re-used when dequeueReusableCellWithIdentifier
Retaining an object means the retain count increases by one. This means the instance of the object will be kept in memory until it’s retain count drops to zero. The property will store a reference to this instance and will share the same instance with anyone else who retained it too. Copy means the object will be cloned with duplicate values. It is not shared with any one else.
Method swizzling allows the implementation of an existing selector to be switched at runtime for a different implementation in a classes dispatch table. Swizzling allows you to write code that can be executed before and/or after the original method. For example perhaps to track the time method execution took, or to insert log statements
A category is a way of adding additional methods to a class without extending it. It is often used to add a collection of related methods. A common use case is to add additional methods to built in classes in the Cocoa frameworks. For example adding async download methods to the UIImage class.
What is the difference between viewDidLoad and viewDidAppear? Which should you use to load data from a remote server to display in the view?
viewDidLoad is called when the view is loaded, whether from a Xib file, storyboard or programmatically created in loadView. viewDidAppear
What considerations do you need when writing a UITableViewController which shows images downloaded from a remote server?
- Only download the image when the cell is scrolled into view, i.e. when cellForRowAtIndexPath is called.
- Downloading the image asynchronously on a background thread so as not to block the UI so the user can keep scrolling.
- When the image has downloaded for a cell we need to check if that cell is still in the view or whether it has been re-used by another piece of data. If it’s been re-used then we should discard the image, otherwise we need to switch back to the main thread to change the image on the cell.
- Other good answers will go on to talk about offline caching of the images, using placeholder images while the images are being downloaded.
A protocol is similar to an interface from Java. It defines a list of required and optional methods that a class must/can implement if it adopts the protocol. A common use case is providing a DataSource for UITableView or UICollectionView.
KVC stands for Key-Value Coding. It's a mechanism by which an object's properties can be accessed using string's at runtime rather than having to statically know the property names at development time. KVO stands for Key-Value Observing and allows a controller or class to observe changes to a property value.
Blocks are a way of defining a single task or unit of behavior without having to write an entire Objective-C class. Under the covers Blocks are still Objective C objects. They are a language level feature that allow programming techniques like lambdas and closures to be supported in Objective-C. Creating a block is done using the ^ { } syntax: It is essentially a function pointer which also has a signature that can be used to enforce type safety at compile and runtime.
- NSThread creates a new low-level thread which can be started by calling the start method.
- NSOperationQueue allows a pool of threads to be created and used to execute NSOperations in parallel. NSOperations can also be run on the main thread by asking NSOperationQueue for the mainQueue.
- GCD or Grand Central Dispatch is a modern feature of Objective-C that provides a rich set of methods and API's to use in order to support common multi-threading tasks. GCD provides a way to queue tasks for dispatch on either the main thread, a concurrent queue (tasks are run in parallel) or a serial queue (tasks are run in FIFO order).
Both are used for sending values and messages to interested parties. A delegate is for one-to-one communication and is a pattern promoted by Apple. In delegation the class raising events will have a property for the delegate and will typically expect it to implement some protocol. The delegating class can then call the _delegate_s protocol methods. Notification allows a class to broadcast events across the entire application to any interested parties. The broadcasting class doesn't need to know anything about the listeners for this event, therefore notification is very useful in helping to decouple components in an application.
There's no right or wrong answer to this, but it's great way of seeing if you understand the benefits and challenges with each approach. Here's the common answers I hear:
- Storyboard's and Xib's are great for quickly producing UI's that match a design spec. They are also really easy for product managers to visually see how far along a screen is.
- Storyboard's are also great at representing a flow through an application and allowing a high-level visualization of an entire application.
- Storyboard's drawbacks are that in a team environment they are difficult to work on collaboratively because they're a single file and merge's become difficult to manage.
- Storyboards and Xib files can also suffer from duplication and become difficult to update. For example if all button's need to look identical and suddenly need a color change, then it can be a long/difficult process to do this across storyboards and xibs.
- Programmatically constructing UIView's can be verbose and tedious, but it can allow for greater control and also easier separation and sharing of code. They can also be more easily unit tested.
How would you securely store private user data offline on a device? What other security best practices should be taken?
- If the data is extremely sensitive then it should never be stored offline on the device because all devices are crackable.
- The keychain is one option for storing data securely. However it's encryption is based on the pin code of the device. User's are not forced to set a pin, so in some situations the data may not even be encrypted. In addition the users pin code may be easily hacked.
- A better solution is to use something like SQLCipher which is a fully encrypted SQLite database. The encryption key can be enforced by the application and separate from the user's pin code.
Other security best practices are:
- Only communicate with remote servers over SSL/HTTPS.
- If possible implement certificate pinning in the application to prevent man-in-the-middle attacks on public WiFi.
- Clear sensitive data out of memory by overwriting it.
- Ensure all validation of data being submitted is also run on the server side.
- get the exact steps to reproduce it.
- find out the device, iOS version.
- do they have the latest version?
- get device logs if possible.
Once you can reproduce it or have more information then start using tooling. Let's say it crashes because of a memory leak, I'd expect to see someone suggest using Instruments leak tool. A really impressive candidate would start talking about writing a unit test that reproduces the issue and debugging through it.
struct IntStack {
var items = [Int]()
func add(x: Int) {
items.append(x) // Compile time error here.
}
}
Structures are value types. By default, the properties of a value type cannot be modified from within its instance methods. However, you can optionally allow such modification to occur by declaring the instance methods as ‘mutating’; e.g.:
- What is ManagedObject
- What is Persistence store coordinator
- What is Managed Object Context?
- How we can do multithreading with core data?
- How to transfer manage object from one thread to another thread?
- what is CoreData and what do we use it for
- is CoreData == sqlite or some wrapper?
- what types of stores does core data support
- What is the minimum necessary classes and relationship between them?
- Can the NSPersistentStoreCoordinator have more persistent stores?
- What about multi-threading and core data usage
- What is an NSManagedObjectId
- What is lazy loading, how does this relate to core data, situations when this can be handy
- How to read only a few attributes of an entity
- What is a fetchedresultcontroller
- How to synchronize contexts
- How could one simulate an NSManagedObject (dynamic properties)
- What is relation
Answer to this question covers understanding of Hash, memory management. Should be O(1) set, get and search