Swift Extension for [String]

Swift extension example

Creating an extension

Add a new swift file with File > New > File... > iOS > Source > Swift File. You can call it what you want.

The general naming convention is to call it TypeName+NewFunctionality.swift.

Sample Image

Example 1 - Double

Double+Conversions.swift

import Swift // or Foundation

extension Double {

func celsiusToFahrenheit() -> Double {
return self * 9 / 5 + 32
}

func fahrenheitToCelsius() -> Double {
return (self - 32) * 5 / 9
}
}

Usage:

let boilingPointCelsius = 100.0
let boilingPointFarenheit = boilingPointCelsius.celsiusToFahrenheit()
print(boilingPointFarenheit) // 212.0

Example 2 - String

String+Shortcuts.swift

import Swift // or Foundation

extension String {

func replace(target: String, withString: String) -> String {
return self.replacingOccurrences(of: target, with: withString)
}
}

Usage:

let newString = "the old bike".replace(target: "old", withString: "new")
print(newString) // "the new bike"

Here are some more common String extensions.

Example 3 - UIColor

UIColor+CustomColor.swift

import UIKit

extension UIColor {

class var customGreen: UIColor {
let darkGreen = 0x008110
return UIColor.rgb(fromHex: darkGreen)
}

class func rgb(fromHex: Int) -> UIColor {

let red = CGFloat((fromHex & 0xFF0000) >> 16) / 0xFF
let green = CGFloat((fromHex & 0x00FF00) >> 8) / 0xFF
let blue = CGFloat(fromHex & 0x0000FF) / 0xFF
let alpha = CGFloat(1.0)

return UIColor(red: red, green: green, blue: blue, alpha: alpha)
}
}

See here also.

Usage:

view.backgroundColor = UIColor.customGreen

Sample Image

Notes

  • Once you define an extension it can be used anywhere in your app just like the built in class functions.
  • If you are not sure of exactly what the function or property syntax should look like, you can Option+click a similar built in method. For example, when I Option+clicked UIColor.greenColor I see the declaration is class func greenColor() -> UIColor. That gives me a good clue for how to set up my custom method.
  • Apple Documentation for Extensions
  • In Objective-C extensions are known as categories.

Swift extension for [String]?

You could follow the declaration of joinWithSeparator (Cmd-click on it) and find that it is defined as an extension of the protocol SequenceType instead of the type Array.

// swift 2:
extension SequenceType where Generator.Element == String {
public func joinWithSeparator(separator: String) -> String
}

(Note: In Xcode 8 / Swift 3 if you Cmd-click on join(separator:) you will land on Array even if it is still implemented inside Sequence, but that won't invalidate the idea below)

We could do the same with your function, where we extend a protocol adopted by Array instead of Array itself:

// swift 2:
extension CollectionType where
Generator.Element == String,
SubSequence.Generator.Element == String,
Index: BidirectionalIndexType
{
func joinWithCommas() -> String {
switch count {
case 0, 1, 2:
return joinWithSeparator(" or ")
default:
return dropLast(1).joinWithSeparator(", ") + ", or " + last!
}
}
}

// swift 3:
extension BidirectionalCollection where
Iterator.Element == String,
SubSequence.Iterator.Element == String
{
func joinWithCommas() -> String {
switch count {
case 0, 1, 2:
return joined(separator: " or ")
default:
return dropLast().joined(separator: ", ") + ", or " + last!
}
}
}

Note:

  • we extend CollectionType to be able to use count
  • we constraint Generator.Element == String to use joinWithSeparator
  • we constraint SubSequence.Generator.Element == String to ensure dropLast(1) can use joinWithSeparator. dropLast(1) returns the associated type SubSequence.
  • we constraint Index: BidirectionalIndexType to use last.

Swift: How to add a class method in 'String extension

Class and static functions are not called on an instance of a class/struct, but on the class/struct itself, so you can't just append a string to a class.

Apple Documentation:

Within the body of a type method, the implicit self property refers to
the type itself, rather than an instance of that type.

You can, however, append a string to a variable instance of a String using the mutating keyword:

extension String {
mutating func aaa() {
self += "hello"
}
}

let foo = "a"
foo.aaa() // ERROR: Immutable value of type 'String' only has mutating members named 'aaa'

var bar = "b"
bar.aaa() // "bhello"

If you are trying to use a pointer to a string as a parameter, you can use the inout keyword to alter the inputed string:

extension String {
static func aaa(inout path: String) {
path += "Hello"
}
}

var foo = "someText"
String.aaa(&foo)
foo //someTextHello

Call String extension including function written in Swift from Objective-C

A Swift class, extension, or protocol can only be represented in Objective-C if it's convertible or marked explicitly with @objc.. which means it requires all parameters to be convertible to Objective-C as well.

struct also cannot be converted so that leaves us with just classes alone (IE: extensions on classes and concrete classes) and to mark a class @objc, it must inherit NSObject.

Example:

@objc
extension NSString {
func asImage(withAttributes attributes: [NSAttributedString.Key: Any]? = nil, size: CGSize = .zero) -> UIImage? {
let size = size == .zero ? self.size(withAttributes: attributes!) : size
if #available(iOS 10.0, *) {
return UIGraphicsImageRenderer(size: size).image { _ in
self.draw(in: CGRect(origin: .zero, size: size),
withAttributes: attributes!)
}
} else {
// Fallback on earlier versions
return nil
}
}
}

Notice that I changed the CGSize parameter to non-optional and compared against zero instead..

Also note that I marked it @objc and changed it to an extension on NSString because String itself cannot be converted to Objective-C as it's a struct!

Then in Objective-C you can call it like so:

[str asImageWithAttributes:@{....} size:CGSizeZero];

or whatever parameters you want..

How can I design a string type extension that represents a day of the week and returns the corresponding number? On Swift

You better create a enumeration where its rawValue is a string and add a computed property to return a value:

extension Calendar {
enum Weekday: String, CaseIterable, CustomStringConvertible {
case sunday, monday, tuesday, wednesday, thursday, friday, saturday
var description: String { rawValue.capitalized }
var value: Int { Self.allCases.firstIndex(where: {$0.rawValue == rawValue})! + 1 }
}
}


let monday = Calendar.Weekday.monday
print(monday) // Monday
print(monday.value) // 2

If you need to convert the string to a number you can initialize a new case and return its value:

extension String {
var weekday: Int? { Calendar.Weekday(rawValue: lowercased())?.value }
}


"monday".weekday  // 2
"Monday".weekday // 2
"MONDAY".weekday // 2

How to add custom init for String extension?

Edit: Don't format currencies yourself.

However you might think currencies are formatted, you're almost certainly wrong. Just compare:

  • US/Canada: $3,490,000.89
  • French Canadian: 3 490 000,89 $
  • France: 3 490 000,89 €
  • Germany: 3.490.000,89 €

Instead, use NumberFormatter with numberStyle set to .currency, with a specified locale.

let currencyFormatter = NumberFormatter()
currencyFormatter.usesGroupingSeparator = true
currencyFormatter.numberStyle = .currency
currencyFormatter.locale = Locale.current
let priceString = currencyFormatter.string(from: 9999.99)!
print(priceString) // Displays $9,999.99 in the US locale

Original answer:

The initializers (and mutating methods) of value types can simply assign directly to self:

import Foundation

extension String {
init(_ amount: Double, decimalPlaces: UInt) {
let currencyAmount = String(format: "%\(decimalPlaces).f", amount)
let currencySign = NSLocalizedString("Defaults.CurrencySign", comment: "currency sign")
self = "\(currencySign)\(currencyAmount)"
}
}

let price = Double(155.15)
let formattedPrice = String(price, decimalPlaces: 2) // formattedPrice = "$155.15"

String extension for matching regular expression

.characters are gone. You can use the string itself directly.

Change self.characters.indices to self.indices

Change self.rangeOfString(expression, options: NSString.CompareOptions.RegularExpressionSearch, range: nil, locale: nil) to self.range(of: expression, options: .regularExpression, range: nil, locale: nil)

And lastly, you can use NSRegularExpression instead of recursively call the function, but note that it can throw some errors, so you should handle it somehow. Use this extension:

extension String {
func stringsMatchingRegularExpression(expression regex: String) throws -> [String] {
let regex = try NSRegularExpression(pattern: regex)
let results = regex.matches(in: self,
range: NSRange(self.startIndex..., in: self))
return results.map {
String(self[Range($0.range, in: self)!])
}
}
}

- More Swifty-Style:

extension String {

func matching(expression regex: @autoclosure () throws -> NSRegularExpression) rethrows -> [String] {
let results = try regex().matches(in: self, range: NSRange(self.startIndex..., in: self))
return results.map {
String(self[Range($0.range, in: self)!])
}
}

func matching(pattern regexPattern: String) throws -> [String] {
return try self.matching(expression: NSRegularExpression(pattern: regexPattern))
}
}

How to add an optional string extension?

In Swift 3.1 you can add an extension to optional values as well:

extension Optional where Wrapped == String {
var isBlank: Bool {
return self?.isBlank ?? true
}
}


Related Topics



Leave a reply



Submit