Skip to main content

What features of Swift do you like or dislike?

· One min read
Ace the iOS Interview
Aryaman Sharda
Sources & Resources

Main Source: 🔗 Ace the iOS Interview

Additional Sources:

Further Reading:

TL/DR

Unfortunately, there’s no one-size-fits-all answer for a question like this. These types of open-ended questions help the interviewer gauge your understanding and level of depth with a language or technology.

Is the candidate able to compare and contrast it with other languages that solve some implementation problems differently? Does the candidate follow Swift's development? Can they defend their technical opinions?

A common answer to this question is that Swift's optional chaining functionality violates the Law of Demeter.

What is a memory leak?

· One min read
Ace the iOS Interview
Aryaman Sharda
Sources & Resources

Main Source: 🔗 Ace the iOS Interview

Additional Sources:

Further Reading:

TL/DR

Memory leaks occur when a program incorrectly manages memory allocations such that memory that is no longer needed is not released. Additionally, it is also possible for a memory leak to occur when an object is in memory, but cannot be accessed by the running application.

In iOS, most memory leaks are a result of retain cycles.

This occurs when two entities keep astrongreferenceto one another. Since these entities' respective retain counts would be non-zero, ARC (automatic reference counting) would be unable to release either one.

The advantage of keywords likeweakorunownedisthat they allow us to create references to other objects without affecting their retain count. As a result, most memory leaks can be mitigated by making the offending referenceweakorunowned.

If we need to debug a memory leak, we can use Xcode’s Memory Graph Tool or the Leaks profiling template within Instruments.

What is a placeholder constraint?

· One min read
Ace the iOS Interview
Aryaman Sharda
Sources & Resources

Main Source: 🔗 Ace the iOS Interview

Additional Sources:

Further Reading:

TL/DR

There may be cases where a constraint can only meaningfully be set at runtime. Perhaps you don't know which subview to constrain a constraint too or maybe you don't know what the constant value of the constraint should be.

If you choose to omit this constraint at compile time, AutoLayout might complain about ambiguous constraints or an unsatisfiable layout. By using placeholder constraints, we can sidestep this issue.

Simply put, a placeholder constraint is a constraint that exists only at design time. They are not included in the layout when the app runs.

You typically add placeholder constraints when you plan to dynamically add constraints at runtime. By temporarily adding the constraints needed to create a non-ambiguous, satisfiable layout, you clear out any warnings or errors in Interface Builder.

What is a race condition?

· 2 min read
Ace the iOS Interview
Aryaman Sharda
Sources & Resources

Main Source: 🔗 Ace the iOS Interview

Additional Sources:

Further Reading:

TL/DR

A race condition occurs when there are multiple threads accessing the same memory concurrently and at least one of the threads is trying to update the information stored there (a.k.a a write task).

Imagine we had 3 threads, A, B, and C all accessing the same memory. In this example, A & B are simply reading the value at this location while C is trying to update the value stored there.

The order in which each thread completes their task can greatly influence the results of the other threads.

For example, if the task running on C finishes prior to the tasks on A & B, then A & B will both be seeing the updated value. Otherwise, if C finishes afterwards, A & B will have completed their tasks on what is now out of date information.

The order in which these threads complete their task is entirely dependent on the operating system’s available resources, the respective thread’s priority level, and in how the operating system’s scheduler schedules these operations.

As you can imagine, this would introduce some variability with our code’s execution and we now have a race condition on our hands; whichever thread happens to finish first can wildly and unpredictably influence the state of our application.

If all 3 threads were just reading the value, we’d have no issues.

Fortunately, Xcode provides us with the Thread Sanitizer tool to help us debug issues involving race conditions. This tool can be enabled by editing your target’s scheme and will detect race conditions at runtime.

What is a raw value in an enum?

· 3 min read
Ace the iOS Interview
Aryaman Sharda
Sources & Resources

Main Source: 🔗 Ace the iOS Interview

Additional Sources:

Further Reading:

TL/DR

Enumerations provide a common type for a group of related values thereby enabling you to work with those values type-safely within your code.

While we can use associated values to relate some required data to an enum case, we can use an enum ’s rawValue property in instances where a hard-coded default value will suffice.

Here, ASCIIControlCharacter specifies that the type of its rawValue is going to be a Character.

This, in turn, requires us to provide a hard-coded Character for every case in our enum. So, we can easily link an ASCII character to its respective enum case.

enum ASCIIControlCharacter: Character {
case tab = "\t"
case lineFeed = "\n"
case carriageReturn = "\r"
}

By default, the specified rawValue type can be a String, Character, Integer, or Float, but you can add support for a custom type by adding conformance to RawRepresentable.

The hard-coded value you assign must be unique within the enum’s declaration.

If our enumeration’s rawValue is an Integer or a String,Swift will automatically assign default values for us. However, we’re still able to override the default values if need be.

When it comes toIntegers, the implicit value foreach case is one more than the last. If no value is set for the first case, therawValuewillstart counting up from 0.

Consider thisenumthat specifies the planets and their respective position from the Sun:

enum Planet: Int {
case mercury = 1 , venus, earth, mars, jupiter, saturn, uranus, neptune
}

Since we’ve specified an explicit value of 1 for mercury(instead of the Swift default of 0), Planet.mercury’s rawValue will be 2, Planet.earth will be 3, and so on.

In the case of a String, Swift will set the default rawValue to match the enum case’s name. In the following example, we don’t need to explicitly provide any rawValues as the Swift defaults will work for us.

enum CompassPoint: String {
case north, south, east, west
}

CompassPoint.north.rawValue will be “north”, CompassPoint.south.rawValue will be “south”, and so on.

If we define an enumeration with rawValue support, Swift will automatically add an initializer that allows us to go from the rawValue to the corresponding type.

For example, we could create a reference to Planet.uranus by simply writing:

let possiblePlanet = Planet(rawValue: 7 )
// possiblePlanet is of type Planet? and equals Planet.uranus

Since not all rawValues (ex. Planet(rawValue: 20))can be mapped to a corresponding enum case, using this initializer will return an Optional.

That’s why possiblePlanet is a Planet?.

What is a unit test?

· One min read
Ace the iOS Interview
Aryaman Sharda
Sources & Resources

Main Source: 🔗 Ace the iOS Interview

Additional Sources:

Further Reading:

TL/DR

A unit test is a type of automated test used to validate the correctness of a piece of code by providing an exhaustive list of inputs and ensuring that the expected outputs are returned.

Xcode provides easy support for writing unit tests by way of theXCTestframework. In our app’s testing target, we could write a simple test like this and assert that the output from the function call matches our expected output:

func testOnlyEvenNumbersFilter() {
let input = [ 2 , 3 , 4 , 5 , 6 , 7 ]
let onlyEvens = Math.onlyEvens(input)
XCTAssertEqual([ 2 , 4 , 6 ], onlyEvens)
}

Note: When you’re creating tests in your testing target, the first word of the function name needs to betestin order for Xcode to register itas a unit test.

Unit testing can be a great way to protect our codebase against regressions and is far more scalable than relying on manual testing alone.

What is a view’s intrinsic content size?

· One min read
Ace the iOS Interview
Aryaman Sharda
Sources & Resources

Main Source: 🔗 Ace the iOS Interview

Additional Sources:

Further Reading:

TL/DR

All UIViews have an .intrinsicContentSize property that specifies the amount of space the UIView needs to show its content in an ideal manner.

If you've ever used UITableView.automaticDimension,this is deferring to the UITableViewCell's intrinsic content size to figure out the appropriate height for the cell.

As another example, if you had a UILabel with a customfont and word wrapping enabled, the intrinsic content size would be the size needed to show all of the text without any truncation.

What is a .dSYM file?

· 3 min read
Ace the iOS Interview
Aryaman Sharda
Sources & Resources

Main Source: 🔗 Ace the iOS Interview

Additional Sources:

Further Reading:

TL/DR

Whenever we upload our app to Apple, we remove some information (called symbols) from the compiled executable which specify exactly what functions and variables are being referenced.

This intentional process of removing this data from our executable can not only help reduce the size of our application's binary, but also helps in making our application more difficult to reverse engineer.

Without the inclusion of these symbols, our crash logs look like this:

0 libswiftCore.dylib 0x000000018f3c93800x18f394000 + 217984
1 libswiftCore.dylib 0x000000018f3c93800x18f394000 + 217984
2 libswiftCore.dylib 0x000000018f3c88440x18f394000 + 215108
3 libswiftCore.dylib 0x000000018f3a74e00x18f394000 + 79072
4 libswiftCore.dylib 0x000000018f3ab0d80x18f394000 + 94424
5 F49088168M 0x00000001045ac7500x104590000 + 116560
6 F49088168M 0x00000001045b79040x104590000 + 162052
7 F49088168M 0x00000001045b897c0x104590000 + 166268
8 F49088168M 0x000000010459d9140x104590000 + 55572
9 F49088168M 0x00000001045a0e700x104590000 + 69232
10 F49088168M 0x00000001045a0f4c0x104590000 + 69452

Clearly, it’s hard to tell what’s going on - all we see are memory addresses.

That’s where the .dSYM file comes in.

The .dSYM file (debug symbol file) contains the informationrequired to convert a stack-trace into a human-readable format. This file is automatically created with every release build and is used by Xcode to put the symbols back into the crash report thereby allowing you to read it properly.

Through a process known as re-symbolication, we can leverage our .dSYM file to convert our crash logs to something like this instead:

0 libswiftCore.dylib 0x000000018f3c9380 closure # 1 in closure # 1 in closure # 1 in _assertionFailure+ 217984 (_:_:file:line:flags:) + 452
1 libswiftCore.dylib 0x000000018f3c9380 closure # 1 in closure # 1 in closure # 1 in _assertionFailure+ 217984 (_:_:file:line:flags:) + 452
2 libswiftCore.dylib 0x000000018f3c8844 _assertionFailure+ 215108 (_:_:file:line:flags:) + 468
3 libswiftCore.dylib 0x000000018f3a74e0 _ArrayBuffer._checkInoutAndNativeTypeCheckedBounds+ 79072 (_:wasNativeTypeChecked:) + 208
4 libswiftCore.dylib 0x000000018f3ab0d8 Array.subscript.getter + 84
5 F49088168M 0x00000001045ac750 static ELM327ResponseManager.getResponse(responseStr:obd2Protocol:) + 116560 (ELM327ResponseManager.swift: 27 )
6 F49088168M 0x00000001045b7904 ELM327Client.dataInput(_:characteristicUuidStr:) + 162052 (ELM327Client.swift: 56 )
7 F49088168M 0x00000001045b897c protocol witness for BLEClientInputPort.dataInput(_:characteristicUuidStr:) in conformance ELM327Client + 166268 (<compiler-generated>:0)
8 F49088168M 0 x000000010459d914 BLEConnection.peripheralDataReceived(data:characteristicUuidStr:) + 55572 (BLEConnection.swift:124)
9 F49088168M 0 x00000001045a0e70 BLEConnection.peripheral(_:didUpdateValueFor:error:) + 69232 (BLEConnection.swift:293)
10 F49088168M 0 x00000001045a0f4c @objc BLEConnection.peripheral(_:didUpdateValueFor:error:) + 69452 (<compiler-generated>:0)

You’ll see that our crash logs now contain real method and variable names which makes debugging far easier.

Some services, like Crashlytics, will automatically re-symbolicate the crash reports for you so they're more human readable. This process allows us to ensure our crash logs are obfuscated for everyone else, but still readable and useful to us as developers.

Simply put, removing these symbols from our executable helps us ensure that our app is not only difficult to reverse engineer, but also allows us to reduce our application’s binary size. Then, when needed, we can use the .dSYM file to reversethe process.

What is an anonymous function?

· One min read
Ace the iOS Interview
Aryaman Sharda
Sources & Resources

Main Source: 🔗 Ace the iOS Interview

Additional Sources:

Further Reading:

TL/DR

An anonymous function is a function definition that isn’t bound to an identifier. For example, most closures are considered anonymous functions. They can help make code more readable by allowing you to define all of the relevant logic in one place.

You will have almost certainly used anonymous functions in your own Swift code. Notice how in the following examples, functions like { self.view.backgroundColor = .orange } and { $ 0 * 2 } are defined without explicit function namesattached to them.

func performAnimation() {
self.view.backgroundColor = .orange
}

// Without anonymous function
UIView.animate(withDuration: 1.0, animations: performAnimation)

// With anonymous function
UIView.animate(withDuration: 1.0) {
self.view.backgroundColor = .orange
}

// Without anonymous function
func doubleNumbers(num: Int) -> Int {
return num * 2
}

let input = [ 1 , 2 , 3 , 4 , 5 ]

// Without anonymous function
let result = input.map(doubleNumbers(num:))

// With anonymous function
let resultAnonymous = input.map { $ 0 * 2 }

What is an associated value?

· One min read
Ace the iOS Interview
Aryaman Sharda
Sources & Resources

Main Source: 🔗 Ace the iOS Interview

Additional Sources:

Further Reading:

TL/DR

An associated value is the term used to describe the value accompanying acasein a Swift enum. Associated values allow us to present more nuanceddata by adding contextual information to ourcases.

enum Distance {
case km(Int)
case meters(Int)
case miles(value: Int)
}

Distance.miles(value: 20 )

With Swift, names can be specified for associated values in order to make their use more understandable. Additionally, eachcasecan be associatedwith values of any type and number.

enum Action {
case tackle
case random
case kick(power: Int, speed: Float)
case jump(height: Int)
case shootLasers(useBothLasers: Bool)
}