web-dev-qa-db-fra.com

Des macros dans Swift?

Est-ce que Swift prend actuellement en charge les macros, ou est-il prévu d’ajouter la prise en charge actuellement? Je diffuse actuellement:

Log.trace(nil, function: __FUNCTION__, file: __FILE__, line: __LINE__)

Dans divers endroits de mon code.

54
jhurliman

Dans ce cas, vous devez ajouter une valeur par défaut pour les paramètres "macro".

Swift 2.2 et supérieur

func log(message: String,
        function: String = #function,
            file: String = #file,
            line: Int = #line) {

     print("Message \"\(message)\" (File: \(file), Function: \(function), Line: \(line))")
}

log("Some message")

Swift 2.1 et inférieur

func log(message: String,
        function: String = __FUNCTION__,
        file: String = __FILE__,
        line: Int = __LINE__) {

    print("Message \"\(message)\" (File: \(file.lastPathComponent), Function: \(function), Line: \(line))")
}

log("Some message")

C'est ce que font les fonctions fatalError et assert.

Il n'y a pas d'autres macros à l'exception de la compilation conditionnelle déjà mentionnée dans une autre réponse.

60
Sulthan

Les Apple docs indiquent que:

Déclarez des macros simples en tant que constantes globales et traduisez des macros complexes en fonctions.

Vous pouvez toujours utiliser # if/# else/# endif - mais mon sentiment est qu'ils n'introduiront pas de fonctions macro, le langage n'en a tout simplement pas besoin.

18
ColinE

Depuis XCode 7.3, le __FILE____FUNCTION__ et __LINE__ les constantes de compilation sont devenues les plus belles #file#function et #line respectivement.

5
glenc

lastPathComponent a besoin d'un NSURL, j'ai donc changé le code ci-dessus en ceci:

func log(message: String,
    function: String = __FUNCTION__,
    file: String = __FILE__,
    line: Int = __LINE__) {

        let url = NSURL(fileURLWithPath: file)

        print("Message \"\(message)\" (File: \(url.lastPathComponent ?? "?"), Function: \(function), Line: \(line))")
}

log("some message")
3
Alan Edmonds

Voici une mise à jour Swift 2 réponse.

func LogW(msg:String, function: String = #function, file: String = #file, line: Int = #line){
    print("[WARNING]\(makeTag(function, file: file, line: line)) : \(msg)")
}

private func makeTag(function: String, file: String, line: Int) -> String{
    let url = NSURL(fileURLWithPath: file)
    let className = url.lastPathComponent ?? file
    return "\(className) \(function)[\(line)]"
}

Exemple d'utilisation:

LogW("Socket connection error: \(error)")
3
Daniel Ryan

Les macros sont mauvaises, mais parfois vous en avez juste besoin. Par exemple, j'ai

struct RegionEntity {
    var id: Int!
}

Et je veux placer des instances de cette structure sur Set. Je dois donc le conformer au protocole Hashable.

extension RegionEntity: Hashable {
    public var hashValue: Int {
        return id
    }
}

public func ==(first: RegionEntity, second: RegionEntity) -> Bool {
    return first.id == second.id
}

Génial. Mais que se passe-t-il si j'ai des dizaines de telles structures et que la logique est la même? Je peux peut-être déclarer un protocole et le conformer implicitement à Hashable. Allons vérifier:

protocol Indexable {
    var id: Int! { get }
}

extension Indexable {
    var hashValue: Int {
        return id
    }
}

func ==(first: Indexable, second: Indexable) -> Bool {
    return first.id == second.id
}

Et bien ça marche. Et maintenant, je vais conformer ma structure aux deux protocoles:

struct RegionEntity: Indexable, Hashable {
    var id: Int!
}

Nan. Je ne peux pas faire cela, car Equatable requiert l'opérateur == avec Self et il n'y a pas d'opérateur == pour RegionEntity. Swift m'oblige à copier-coller le code de confirmation pour chaque structure et juste changer le nom. Avec la macro, je pouvais le faire avec une seule ligne.

0
Nikolai Ischuk