Skip to main content

19 questions tagged with "UIKit"

UIKit tag description

View All Tags

What is a view鈥檚 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 Dynamic Type in iOS?

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

Main Source: 馃敆 Ace the iOS Interview

Additional Sources:

Further Reading:

TL/DR

Introduced in iOS 10, Dynamic Type allows developers to automatically scale their application's font size up or down to accommodate users with accessibility issues or users that need increased visibility. It can also accommodate those who can read smaller text allowing more information to appear on the screen.

Developers can choose to support Dynamic Text on a view-by-view basis. If you choose to add support for Dynamic Text, you can usetraitCollection.preferredContentSizeCategory to retrieve the user's preferred content size and modify your UI styling accordingly.

You could also implementtraitCollectionDidChange()which will notify you when the user鈥檚 preferred content size setting changes. Then, you can make whatever additional UI changes you need to make based off of the new value in traitCollection.preferredContentSizeCategory:

override func traitCollectionDidChange(
_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
// Use this property to update your application's text styling
traitCollection.preferredContentSizeCategory
}

If you override this function, make sure you always call super.traitCollectionDidChange(previousTraitCollection)first.

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鈥檙e working with designers daily, it鈥檚 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 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鈥檚 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 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鈥檚 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鈥檚 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鈥檚 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鈥檚 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鈥檚 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鈥檚 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鈥檇 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鈥檚 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鈥檚 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鈥檚 important to understand the differences between the two.

A push transition will add another UIViewController to aUINavigationController鈥檚 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鈥檒l also get the ability to swipe to the right to pop the new UIViewController from the UINavigationController鈥檚 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.

What is the purpose of the reuseIdentifier?

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

Main Source: 馃敆 Ace the iOS Interview

Additional Sources:

Further Reading:

TL/DR

One of the performance optimizations UITableViewsandUICollectionViews make is to only initialize enough cells to fill the user鈥檚 screen. Then, whenever the user scrolls, instead of instantiating a new cell, it can just replace the contents of an existing previously allocated cell the cell that is about to be scrolled off the screen. This approach is not only very performant, but also utilizes less memory.

Imagine a UITableView with multiple custom UITableViewCells.In order to perform the optimization mentioned above, the UITableView needsto be able to quickly find a cell that differs only in content, but shares the same layout.

This is exactly the problem that reuse identifiers solve.

UITableViews use reuse identifiers to understand what rows (if any) differ only in content and not in layout. These cells then become candidates for reuse.

That鈥檚 why if you have a UITableView with multiple UITableViewCell types, you鈥檒l need to register multiple cell reuse identifiers.

tableView.registerClass(MyCustomCell.self, forCellReuseIdentifier: "MyCustomCell")

What is the Responder Chain?

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

Main Source: 馃敆 Ace the iOS Interview

Additional Sources:

Further Reading:

TL/DR

iOS handles all user interaction - touch, press, shake, etc. - through something called the Responder Chain. This is essentially the hierarchy of all objects that have an opportunity to respond to user input.

If a particular object can鈥檛 handle the event, it passes it up to the next item in the chain. This creates a hierarchy of objects that are equipped to handle user interaction of all types.

At the top of this hierarchy, you have theUIApplicationDelegate.

If you鈥檝e ever placed your finger in aUITextFieldon iOS, you鈥檒l notice that the keyboard pops up immediately. From here, all subsequent user interaction events are sent to theUITextField to handle. This is because theUITextFieldis nowthe first responder - it鈥檚 the first object in the hierarchy that has a chance to respond to user interaction.

That鈥檚 why when you want to dismiss the keyboard, you have to write textField.resignFirstResponder() which is the UITextField鈥榮 way of saying that it鈥檚 giving up control and wants to revert back to the previous Responder Chain hierarchy.