Skip to main content

What is the difference between a dynamic library and a static library?

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

Main Source: đź”— Ace the iOS Interview

Additional Sources:

Further Reading:

TL/DR

As your application matures and your application size and launch speed start to suffer, you'll likely find yourself re-evaluating how you integrate libraries into your project.

Libraries and frameworks can either be linked statically or dynamically.

Static libraries are collections of object files (the machine code output after compilation) grouped into a single containing resource. This library will then be copied into the larger executable that eventually runs on your device. If you’ve ever seen a file ending in.a, it’s a static library.

Imagine a suitcase filled with everything you need for your vacation. A static library is similar; everything you need in order to run your application is included in the executable itself. Static libraries cannot contain images, sound files, media,etc. - they can only store code files.

Dynamic libraries (.dylibfiles) are loaded into memorywhen needed instead of being bundled with the executable itself. All iOS and macOS system libraries are actually dynamic.

The main advantage here is that any application that relies on these dynamic libraries will benefit from all future speed improvements and bug fixes in these libraries without having to create a new release. Additionally, dynamic libraries are shared between applications, so the system only needs to maintain one copy of the resource. Since it’s shared and only loaded when needed, invoking code in a dynamic library is slower than a static one.

Let’s take a detailed look at the advantages and disadvantages:

Static Libraries

Pros

  • Guaranteed to be present and the correct version at runtime.
  • The application can run without any external dependencies. You don’t need to monitor library updates since the object files are part of the executable itself. As a result, it becomes standalone and can move from platform to platform.
  • Faster performance compared to calls made to a dynamic library.

Cons

  • Makes the executable larger as it simply just contains more code.
  • Your application will be slower to launch as the library needs to be loaded into memory.
  • Any changes in a static library require the application to be re-compiled and re-distributed.
  • You have to integrate the entire library even if you only rely on a small portion of it.

Dynamic Libraries

Pros

  • Doesn’t increase app size.
  • Better application launch speech as the library is loaded only when needed.
  • Only the relevant section of the library needed for the currently executing code is loaded instead of loading the library in its entirety.

Cons

  • Application may crash if the library updates are not compatible with your application (i.e. business logic / iOS version).
  • Application may crash if the dynamic library cannot be loaded or found.
  • Calls to dynamic library functions are slower than calls made to a static library.

There’s no one size fits all answer. You’ll have to make a pragmatic decision and weigh how much you value performant library calls, app size, launch time, etc. and pick the approach or a hybrid approach that best suits your needs.

What is the difference between a point and a pixel?

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

Main Source: đź”— Ace the iOS Interview

Additional Sources:

Further Reading:

TL/DR

When you’re working with designers daily, it’s important to understand the difference between a point and a pixel.

As you probably know, a pixel is the smallest addressable element of your display or device.

A point is actually a measurement of length and defined as 1 / 72 of an inch. So, on a 72 PPI (pixels per inch) display one point will equal exactly one pixel.

Typically, it's used to measure the height of a font, but can be used to measure any length.

What is the difference between a serial and a concurrent queue?

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

Main Source: đź”— Ace the iOS Interview

Additional Sources:

Further Reading:

TL/DR

We can create both types of queues with the help of DispatchQueue which is built on top of Grand Central Dispatch.

In the case of a serial queue, the tasks will complete in the order they are added to the queue (FIFO); the first task in the queue will complete before the next task begins.

Serial queues are often used to provide synchronized access to a shared resource in order to prevent race conditions.

let serialQueue = DispatchQueue(label: "aryamansharda")

serialQueue.async {
print("This happens first!")
}

serialQueue.async {
print("This happens second!")
}

As you’d expect, the output will be “This happens first!” and then “This happens second!”.

On the other hand, a concurrent queue allows us to start multiple tasks at the same time. However, while we’re starting all of these tasks at the same time, a concurrent queue makes no guarantee about the order in which the tasks willfinish as these tasks are run in parallel.

If you need to establish dependencies between operations or need to ensure a completion order, consider using an OperationQueue or a serialqueue instead.

let concurrentQueue = DispatchQueue(label: "aryamansharda",
attributes: .concurrent)

concurrentQueue.async {
print("I'm added to the queue first!")
}

concurrentQueue.async {
print("I'm added to the queue second!")
}

Even though we’re adding tasks sequentially, it’s plausible for the second task to finish before the first one completes. It’s simply a matter of how the system dispatches the work to the underlying threads and their respective workloads.

What is the difference between Any and AnyObject?

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

Main Source: đź”— Ace the iOS Interview

Additional Sources:

Further Reading:

TL/DR

When we need to work with non-specific types, we have two options to pick from: Any and AnyObject.

Any is used to refer to any instance of a class, struct, function, enum, etc. This is particularly useful when you’re working with a variety of data:

let items: [Any] = [ 1 , UIColor.red, "Blue", Toggle()]

AnyObject is more restrictive as it refers to any instance of a class type. You’ll use this when you only want to work with reference types or when you want to restrict a protocol to only be used with a class type:

protocol ClassOnlyProtocol: AnyObject {...}

In contrast, Any can be used with both value and reference types.

It’s preferable to be as specific as possible about the type you’re using, so I’d encourage you to only use Any or AnyObject when you specifically needthe behavior they provide.

What is the difference between bounds and frame?

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

Main Source: đź”— Ace the iOS Interview

Additional Sources:

Further Reading:

TL/DR

This question is asked frequently during interviews, particularly as part of an initial phone screen or online assessment.

Theboundsof aUIViewis the rectangle expressedas a location(x,y)and size(width, height)relative to its own coordinate system(0,0).

The frame of a UIView is the rectangle expressed as a location(x,y) and size(width, height) relative to the superview it is contained within.

Here’s an example of the difference:

let sampleView = UIView(frame: CGRect(x: 20, y: 420, width: 100, height: 100 ))
sampleView.backgroundColor = .red
view.addSubview(sampleView)

// (20.0, 420.0, 100.0, 100.0)
print("Frame: ", sampleView.frame)
// (0.0, 0.0, 100.0, 100.0)
print("Bounds: ", sampleView.bounds)

let rotatedView = UIView(frame: CGRect(x: 100 , y: 300 , width: 100 ,height: 200 ))

// Rotating the view a bit
let transform = CGAffineTransform(rotationAngle: CGFloat.pi / 4 )
rotatedView.transform = transform
rotatedView.backgroundColor = .blue
view.addSubview(rotatedView)

// (43.933982822017896, 293.93398282201787,
// 212.13203435596424, 212.13203435596427)
print("Frame: ", rotatedView.frame)

// (0.0, 0.0, 100.0, 200.0)
print("Bounds: ", rotatedView.bounds)

The image below should help clarify the difference between theframeand thebounds.

What is the difference between == and ===?

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

Main Source: đź”— Ace the iOS Interview

Additional Sources:

Further Reading:

TL/DR

In the example below, we have a simpleEngineclassthat implements the Equatable protocol. This allows us to provide a custom implementation for the == operator.

We say that two Engines are equal if the horsepower is the same. So, as long as the Int values match, == will return true.

class Engine: Equatable {
var horsepower: Int

init(horsepower: Int) {
self.horsepower = horsepower
}

static func == (lhs: Engine, rhs: Engine) -> Bool {
lhs.horsepower == rhs.horsepower
}
}

let engine1 == Engine(horsepower: 100 )
let engine2 == Engine(horsepower: 100 )
let engine3 == Engine(horsepower: 200 )

engine1 == engine2 // true
engine2 == engine3 // false

With === we’re asking if the objects on either sideof the operator point to the same reference. In other words, do they point to the same place in memory?

In the following example, when we compare engine1 to engineCopy(which is also referencing the same memory location), === returns true.

let engine1 = Engine(horsepower: 200 )
let engine2 = Engine(horsepower: 200 )
let engineCopy = engine1

engine1 === engineCopy // true
engine2 === engineCopy // false

However, in the second check, we can see that engine2 and engineCopy are pointing to entirely different objects, so even though thehorsepoweris the same,=== returns false.

What is the difference between is, as, as?, and as!?

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

Main Source: đź”— Ace the iOS Interview

Additional Sources:

Further Reading:

TL/DR

Typecasting is a method of changing an entity from one data type to another.

These keywords are used to support typecasting in Swift and allow us to check the type of an instance or to treat an instance as one of the classes in its class hierarchy. This definition will hopefully make much more sense when we look at some examples.

It may be useful to understand the following terminology:

Upcasting: You cast an instance from a subclass toa superclass Downcasting: You cast an instance from a superclassto a subclass

Casting doesn’t actually modify the instance or change its values. The underlying instance remains the same; it’s simply treated and accessed as an instance of the type to which it has been cast.

Here’s the class hierarchy we’ll use in the following examples:

protocol Animal {}
class Mammal: Animal {}

class Dog: Mammal {}
class Cat: Mammal {}

is (typecheck operator) Use the typecheck operator, is, to check whether an instance is of a certain subclass type:

let dog = Dog()

// Output: true
print(dog is Animal)

// Output: true
print(dog is Mammal)

// Output: false
print(dog is Cat)

It’s important to recognize that this keyword only returns a boolean. It does not perform any conversion - it simply checks to see if a potential type conversion could occur.

This keyword isn’t very popular in Swift as you can always write an equivalent expression using an if let and as? instead which would have the added benefit of actually performing the conversion for you.

We’ll see an example of this shortly.

as (upcasting operator) The as operator allows us to upcast from a subclassto superclass (i.e. Dog to Animal).

The compiler must be able to guarantee the validity of the cast when we use this operator.

So, we’ll typically use it for conversions we know the compiler will be able to verify like String to NSString, NSDate to Date, or casting an objectback to its parent class type.

let animal: [Animal] = [Dog() as Animal, Cat() as Animal, Mammal() as Animal]

// Output: [ExampleApp.Dog, ExampleApp.Cat, ExampleApp.Mammal]
print(animal)

as? (conditional cast operator) Similar to the as operator, as? also attempts to converta class’s type, but will return nil if the conversion fails.

Use the as? operator when you aren’t sure if the casting operation will succeed. In the example below, the attempt to downcast mammal to Dog succeeds,but attempting to cast mammal to Cat evaluates to nil.

let mammal: Mammal = Dog()

if let dog = mammal as? Dog {
// Valid
print(dog)
}

// This expression will evaluate to nil
if let cat = mammal as? Cat {
print(cat)
} else {
print("Downcasting failed!")
}

as! (forced casting keyword) This operator is known as the force downcasting operator and, like all other force unwrapping, will trigger a runtime error if the downcast conversion fails.

Make sure you only use this when you know the downcast will succeed!

let mammal: Mammal = Dog()

// Downcast succeeds
let dog = mammal as! Dog

// Triggers runtime error
let cat = mammal as! Cat

What is the difference between layoutIfNeeded() and setNeedsLayout()?

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

Main Source: đź”— Ace the iOS Interview

Additional Sources:

Further Reading:

TL/DR

Building off the previous answer, let’s take a closer look at the differences between layoutIfNeeded() and setNeedsLayout().

setNeedsLayout() Calling this function tells the system that you want to invalidate the current layout of the view and trigger a layout update in the next update cycle. This function should only be called on the Main Thread.

This function will return immediately as it simply queues this task onto the Main Thread and then returns. Since the actual work is only done on the next update cycle, you can use this function to invalidate the layout of multiple views at once. Consolidating all of your layout updates to one update cycle is far better for performance.

In simple terms, this function will set a flag in the UIView that will indicate to the system that the view’s layout needs to be updated. This, in turn, will schedule a call to layoutIfNeeded() which will check the status of this flag before proceeding.

Then, assuming the view’s layout does in fact need to be updated, layoutIfNeeded() will call layoutSubviews() to update the view prior to the next update cycle.

layoutIfNeeded() Unlike setNeedsLayout(), layoutIfNeeded() tells the system that we want to apply the view’s pending layout changes immediately and we donot want to wait for the next update cycle.

So, whenever you need to apply layout changes immediately, uselayoutIfNeeded() not setNeedsLayout().

When using Auto Layout, the layout engine updates the position of views as needed to satisfy changes in constraints. Using the view that receives the layoutIfNeeded() message as the root view, this method lays out the view subtree starting at the root. If no layout updates are pending, this method exits without modifying the layout or calling any layout-related callbacks.

What is the difference between layout margins and directional layout margins?

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

Main Source: đź”— Ace the iOS Interview

Additional Sources:

Further Reading:

TL/DR

layoutMargins is a property of a UIView that allows the developer to specify the top,left, bottom, and right insets for a view’s margin. The system defaults a UIView to an inset of 16 pixels on all edges.

override func viewDidLoad() {
super.viewDidLoad()

greetingLabel.translatesAutoresizingMaskIntoConstraints = false

greetingLabel.centerYAnchor.constraint(
equalTo: view.centerYAnchor).isActive = true
greetingLabel.leadingAnchor.constraint(
equalTo: view.layoutMarginsGuide.leadingAnchor).isActive = true
greetingLabel.trailingAnchor.constraint(
equalTo: view.layoutMarginsGuide.trailingAnchor).isActive = true
}

As you can see, theUIViewis inset 16 pixels from the left.

We can easily customize it with our own values:

override func viewDidLoad() {
super.viewDidLoad()


view.layoutMargins = UIEdgeInsets(top: 0 , left: 100 ,
bottom: 0 , right: 0 )

greetingLabel.translatesAutoresizingMaskIntoConstraints = false
greetingLabel.centerYAnchor.constraint(
equalTo: view.centerYAnchor).isActive = true
greetingLabel.leadingAnchor.constraint(
equalTo: view.layoutMarginsGuide.leadingAnchor).isActive = true
greetingLabel.trailingAnchor.constraint(
equalTo: view.layoutMarginsGuide.trailingAnchor).isActive = true
}

All constraints relative to thelayoutMarginswillnow honor the custom insets we specified above:

But, there’s a silent issue here. What happens if our device uses a language that lays out right to left like Hebrew or Farsi? In that case, we’d want ourleftedge inset to start from the right-hand side and vice-versa.

We can use directionalLayoutMargins to fix this. This property was introduced in iOS 11 and should always be used in place of layoutMargins.

It allows us to specify constraints and custom insets on a UIView while taking into account the current language’s direction:

view.directionalLayoutMargins =
NSDirectionalEdgeInsets(top: 0 , leading: 100 , bottom: 0 , trailing: 0 )

greetingLabel.translatesAutoresizingMaskIntoConstraints = false
greetingLabel.centerYAnchor
.constraint(equalTo: view.centerYAnchor).isActive = true
greetingLabel.leadingAnchor
.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor)
.isActive = true
greetingLabel.trailingAnchor
.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor)
.isActive = true

Notice the change in type directionalLayoutMargins are of the NSDirectionalEdgeInsets type instead and the left and right parameters are now replaced with leading and trailing.

When we update our implementation to use directionalLayoutMargins,we can see that our margins now honor the layout direction of the device’s primary language:

The system keeps the layoutMargins property of the rootUIView in sync with the directionalLayoutMargins. So, the left inset will automatically take the value of the leading or trailing margin depending on the layout direction.

What is the difference between pushing and presenting a new view?

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

Main Source: đź”— Ace the iOS Interview

Additional Sources:

Further Reading:

TL/DR

Both pushing and presenting presentation styles have their own default behavior and conventions, so it’s important to understand the differences between the two.

A push transition will add another UIViewController to aUINavigationController’s view hierarchy. The UIViewController that originates thepush should belong to the same UINavigationControlleras the UIViewController thatis being added to the stack.

With a push transition, you will automatically get a back button from the new UIViewController to the previous one. Additionally,you’ll also get the ability to swipe to the right to pop the new UIViewController from the UINavigationController’s view hierarchy without writing any additional code.

Push transitions are only available to UIViewControllers that are embedded in a UINavigationController instance.

Now, turning to presenting a UIViewController(i.e.modal transition).

This is simply the case of one UIViewController presentinganother UIViewController vertically over itself - neither of these UIViewControllers have to be embedded in a UINavigationController.

The modally presented UIViewController will typically appear without a UINavigationBar or UITabBar unless specified otherwise. Remember,though, that different versions of iOS havedifferent default styling for modally presented views.

Finally, the presenting UIViewController is generally responsible for dismissing any modallypresented UIViewController it presents.