Add custom weight to iOS Font descriptor in Swift

If you use existing fontDescriptor (for example from existing font), it may not working, because of explicit '.name' attribute in fontDescriptor.fontAttributes.

Solution, that works for me (Swift 4):

extension UIFont {
    var bold: UIFont { return withWeight(.bold) }
    var semibold: UIFont { return withWeight(.semibold) }

    private func withWeight(_ weight: UIFont.Weight) -> UIFont {
        var attributes = fontDescriptor.fontAttributes
        var traits = (attributes[.traits] as? [UIFontDescriptor.TraitKey: Any]) ?? [:]

        traits[.weight] = weight

        attributes[.name] = nil
        attributes[.traits] = traits
        attributes[.family] = familyName

        let descriptor = UIFontDescriptor(fontAttributes: attributes)

        return UIFont(descriptor: descriptor, size: pointSize)


let baseFont = UIFont(name: "American Typewriter", size: 20)!
let boldFont = baseFont.bold
let semibold = baseFont.semibold

With Swift 4.1, simply do something like this:

var descriptor = UIFontDescriptor(name: "Helvetica Neue", size: 24.0)
descriptor = descriptor.addingAttributes([UIFontDescriptor.AttributeName.traits : [UIFontDescriptor.TraitKey.weight : UIFont.Weight.light]])
let font = UIFont(descriptor: descriptor, size: 24.0)

UIFont(descriptor: imgFontDescriptor!, size: 24.0) is returning a Font what match with the descriptor. If it can't find a Font match with your description, it returns a default font. Therefore, you can't control your weight manually. It depends on the Font you use. If the Font is support that weight, it will return that.

One more thing, you should use [UIFontDescriptorFamilyAttribute: "Helvetica"]. So it will determine FontName base on FamilyName & your FontWeight.

The correct way is use the constant from Apple lib:

public let UIFontWeightUltraLight: CGFloat
@available(iOS 8.2, *)
public let UIFontWeightThin: CGFloat
@available(iOS 8.2, *)
public let UIFontWeightLight: CGFloat
@available(iOS 8.2, *)
public let UIFontWeightRegular: CGFloat
@available(iOS 8.2, *)
public let UIFontWeightMedium: CGFloat
@available(iOS 8.2, *)
public let UIFontWeightSemibold: CGFloat
@available(iOS 8.2, *)
public let UIFontWeightBold: CGFloat
@available(iOS 8.2, *)
public let UIFontWeightHeavy: CGFloat
@available(iOS 8.2, *)
public let UIFontWeightBlack: CGFloat*/

You should use to determine which font weight that family name is supporting.

In case of Helvetica:

let traits = [UIFontWeightTrait: UIFontWeightLight] // UIFontWeightBold / UIFontWeightRegular
let imgFontDescriptor = UIFontDescriptor(fontAttributes: [UIFontDescriptorFamilyAttribute: "Helvetica"])
imgFontDescriptor = imgFontDescriptor.fontDescriptorByAddingAttributes([UIFontDescriptorTraitsAttribute: traits])