2016-12-15 3 views
1

J'essaie de convertir un programme existant qui utilise une liste de couleurs prédéfinies d'Ojective-C à Swift. Le code original utilisé Selector pour extraire un UIColor basé sur ce nom représenté comme un NSStringComment convertir une chaîne en UIColor dans Swift 3.0?

#define UIColorFromRGB(rgbValue) [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 green:((float)((rgbValue & 0xFF00) >> 8))/255.0 blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0] 

-(UIColor *)getColor:(NSString*)colorName 
{ 
    SEL selColor = NSSelectorFromString(colorName); 
    NSString *errorMessage = [NSString stringWithFormat:@"Invalid color name: %@ !!!", colorName]; 
    NSAssert([UIColor respondsToSelector:selColor] == YES, errorMessage); 
    UIColor *mycolor = [UIColor performSelector:selColor]; 
    return mycolor; 
} 

+ (instancetype)turquoiseColor { 
    return UIColorFromRGB(0x40E0D0); 
} 

+ (instancetype)mediumTurquoiseColor { 
    return UIColorFromRGB(0x48D1CC); 
} 

Cependant, je suis incapable de trouver comment obtenir les mêmes fonctionnalités en utilisant Swift 3.0, ou si l'utilisation du sélecteur est même la meilleure technique.

func UIColorFromRGB(_ rgbValue: UInt) -> UIColor { 
    return UIColor(
     red: CGFloat((rgbValue & 0xFF0000) >> 16)/255.0, 
     green: CGFloat((rgbValue & 0x00FF00) >> 8)/255.0, 
     blue: CGFloat(rgbValue & 0x0000FF)/255.0, 
     alpha: CGFloat(1.0) 
    ) 
} 

extension UIColor { 
    public class var turquoise: UIColor { return UIColorFromRGB(0x40E0D0) } 
} 

extension UIColor { 
    public class var mediumTurquoise: UIColor { return UIColorFromRGB(0x48D1CC) } 
} 

let myColor: UIColor = .turquoise 

let name: String = "turquoise" 
let colorName = "UIColor.\(name)" 
let selector: Selector = NSSelectorFromString(colorName) 

let colorSelected: UIColor = UIColor.perform(selector!) 

Erreur:! Non Perform «Les candidats produisent le type de résultat contextuel prévu « UIColor »

Répondre

1

Vous pouvez créer un ENUM de couleur qui a une valeur par défaut de chaîne:

enum Color: String { 
    case red 
    case blue 
    case green 

    var create: UIColor { 
     switch self { 
      case .red: 
      return UIColor.red 
     case .blue: 
      return UIColor.blue 
     case .green: 
      return UIColor.green 
     } 
    } 
    } 

Comme il a une valeur par défaut de chaîne vous pouvez initialiser l'ENUM avec une chaîne:

guard let color = Color(rawValue: "red") else { "handle invalid color error"; return } 

let colorSelected = color.create //// colorSelected is now UIColor.red 
+0

C'est une bonne réponse, je viens converti mon code pour le tester. Cependant, le fait qu'il y ait duplication des noms de couleurs le rend plus encombrant dans mon code que les autres suggestions, puisque j'ai 230 couleurs nommées. – Steve

+0

voulez-vous dire la duplication des noms de couleur avec le nom des cas enum? Je ne suis pas sûr de comprendre totalement ce que vous entendez par duplication de noms de couleurs. – JustinM

+0

Oui, le fait que chaque nom de couleur doit apparaître deux fois dans l'énumération, une fois dans l'instruction initiale, puis à nouveau dans l'instruction create. Donc, cela complique les choses quand je veux ajouter de nouveaux noms de couleurs, etc. et conduit à plus de lignes de code. Donc, en utilisant ces critères, la suggestion du dictionnaire est l'implémentation la plus compacte. Mais merci, ça m'a fait réfléchir à toutes les options, et j'apprends quelques nouvelles astuces sur le chemin. – Steve

1

Vous pouvez écrire quelque chose de similaire à votre code Objective-C dans Swift comme ceci:

extension UIColor { 
    @objc(turquoiseColor) 
    public class var turquoise: UIColor { return UIColorFromRGB(0x40E0D0) } 
} 

extension UIColor { 
    @objc(mediumTurquoiseColor) 
    public class var mediumTurquoise: UIColor { return UIColorFromRGB(0x48D1CC) } 
} 

let myColor: UIColor = .turquoise 

func getColor(_ name: String) -> UIColor? { 
    let selector = Selector("\(name)Color") 
    if UIColor.self.responds(to: selector) { 
     let color = UIColor.self.perform(selector).takeUnretainedValue() 
     return (color as! UIColor) 
    } else { 
     return nil 
    } 
} 

var name: String = "turquoise" 
if let color = getColor(name) { 
    print(color) //->UIExtendedSRGBColorSpace 0.25098 0.878431 0.815686 1 
} else { 
    print("color with name:\(name) is unavailable") 
} 

Mais l'utilisation de Selector ne semble pas être Swifty.

Vous pouvez simplement préparer un dictionnaire contenant UIColor s:

let myColors: [String: UIColor] = [ 
    "red": .red, 
    "white": .white, 
    //... 
    "turquoise": UIColorFromRGB(0x40E0D0), 
    "mediumTurquoise": UIColorFromRGB(0x48D1CC), 
] 
name = "mediumTurquoise" 
if let color = myColors[name] { 
    print(color) 
} else { 
    print("color with name:\(name) is unavailable") 
} 

Ou la réponse de JustinM est une très bonne suggestion.

+0

Voilà une réponse très complète, elle m'a décollé. J'ai essayé les deux options et les deux fonctionnent. – Steve

1

Utilisez cette extension de UIColor qui ont deux méthodes pour convertir la chaîne RGBA et hexadécimales Chaîne à UIColor

extension UIColor { 


//Convert RGBA String to UIColor object 
//"rgbaString" must be separated by space "0.5 0.6 0.7 1.0" 50% of Red 60% of Green 70% of Blue Alpha 100% 
public convenience init?(rgbaString : String){ 
    self.init(ciColor: CIColor(string: rgbaString)) 
} 

//Convert UIColor to RGBA String 
func toRGBAString()-> String { 

    var r: CGFloat = 0 
    var g: CGFloat = 0 
    var b: CGFloat = 0 
    var a: CGFloat = 0 
    self.getRed(&r, green: &g, blue: &b, alpha: &a) 
    return "\(r) \(g) \(b) \(a)" 

} 
//return UIColor from Hexadecimal Color string 
public convenience init?(hexString: String) { 

     let r, g, b, a: CGFloat 

     if hexString.hasPrefix("#") { 
      let start = hexString.index(hexString.startIndex, offsetBy: 1) 
      let hexColor = hexString.substring(from: start) 

      if hexColor.characters.count == 8 { 
       let scanner = Scanner(string: hexColor) 
       var hexNumber: UInt64 = 0 

       if scanner.scanHexInt64(&hexNumber) { 
        r = CGFloat((hexNumber & 0xff000000) >> 24)/255 
        g = CGFloat((hexNumber & 0x00ff0000) >> 16)/255 
        b = CGFloat((hexNumber & 0x0000ff00) >> 8)/255 
        a = CGFloat(hexNumber & 0x000000ff)/255 
        self.init(red: r, green: g, blue: b, alpha: a) 
        return 
       } 
      } 
     } 

     return nil 
    } 
// Convert UIColor to Hexadecimal String 
func toHexString() -> String { 
    var r: CGFloat = 0 
    var g: CGFloat = 0 
    var b: CGFloat = 0 
    var a: CGFloat = 0 
    self.getRed(&r, green: &g, blue: &b, alpha: &a) 
    return String(
     format: "%02X%02X%02X", 
     Int(r * 0xff), 
     Int(g * 0xff), 
     Int(b * 0xff) 
    ) 
} 

}