GeekerProbe

水滴石穿 Keeping faith.      --- wtlucky's Blog

Swift Hexadecimal Conversion

| Comments

自己的Blog好久没有更新了,一个是因为这半年里要忙着毕业好多事情,再一个就是工作上也很忙,基本就没有时间来为我的Blog增添新的血液了。APPLEWWDC 2014上公布了一门新的编程语言Swift,最近可以说是相当火热,而且在语言热度排名上也是突飞猛进,这是一个集合了N多语言优秀特性于一身的全新语言,它将成为开发iOSMAC的新的选择。并且据说他将会取代Objective-C,但是我觉得并不是这样,不过这也仅仅是一家之谈,至于会不会这样,我们走着瞧。

既然苹果放出了这样一个利器,身为iOS开发者的我也不能落下,APPLE为我们提供了两个文档The Swift Programming LanguageUsing Swift with Cocoa and Objective-C。他们一个是纯语言角度的介绍Swift,包括各种细节语法,另一个则是介绍怎么它怎么与Cocoa交互,如何使用它开发iOSMAC应用,以及如何与现有的程序兼容。学习这样一门全新的技术我还是建议读第一手资料的,虽然现在网络上有好多中文版的资料了吧,但是苹果的文档写的很是通俗易懂,读起来也没有什么困难。而起自己之前有过脚本语言的经验,所以看起来也是很快。

读完两个文档,就做一些实战的内容,先从小程序开始,之前自己写过一个进制转换器,没啥功能,就是提供一个十进制和十六进制互相转换的功能,主要还是为了方便自己在写一些颜色值的时候使用。之前的版本是用Objective-C写的,那么这次就用Swift重写一遍。

这个程序最主要的部分也就是两个进制相互转换的算法了,用Objective-C实现起来很简单,通过一下字符char的运算就能搞定。代码如下:

Hexdecimal To Decimal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
- (NSString *)decimalConvertedFromHexdecimal:(NSString *)hexdecimal
{
  int sum = 0;
  for (int i = 0; i < hexdecimal.length; i ++) {
    char c = [hexdecimal characterAtIndex:i];

    int num = 0;
    if (c >= 'A' && c <= 'F') {
      num = c - 'A' + 10;
    } else if (c >= 'a' && c <= 'f') {
      num = c - 'a' + 10;
    } else if (c >= '0' && c <= '9') {
      num = c - '0';
    } else {
      UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"错误"
      message:@"你提供了非法字符" delegate:nil
      cancelButtonTitle:@"知道了"
      otherButtonTitles:nil];
      [alert show];
      self.beforeConvertTextField.text = @"";
      [self.beforeConvertTextField becomeFirstResponder];
      return nil;
    }

    sum += num * pow(16, hexdecimal.length - i - 1);
  }

  return [NSString stringWithFormat:@"%d", sum];
}
Decimal To Hexdecimal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- (NSString *)hexdecimalConvertedFromDecimal:(NSString *)decimal
{
  int num = [decimal intValue];
  NSMutableString *result = [[NSMutableString alloc] initWithCapacity:0];

  while (num > 0) {
    int tmp = num % 16;
    char c = '0';
    if (tmp > 9) {
      c = 'a' + (tmp - 10);
    } else {
      c = '0' + tmp;
    }
    NSString *character = [NSString stringWithFormat:@"%c", c];
    [result insertString:character atIndex:0];
    num /= 16;
  }

  return result;
}

但是当我使用Swift重写的时候,我进入到了一个很深的坑里,发现这项任务是如此的难做,我定义了这样两个方法,注意方法的参数和返回值:

Swift Code
1
2
3
4
func decimalConvertedFromHexdecimal(hexdecimal: String) -> String? {
}
func hexdecimalConvertedFromDecimal(decimal: String) -> String? {
}

我使用的是Swift提供的String类型,它是由一系列的Character类型的字符组成的,但是这种Character并不是char,他们在处理进制转换这个问题上让我无从下手,也有可能是我还不够熟悉,不知道正确的用法,如果有人知道欢迎告诉我。下面来说一说我遇到的问题,首先在Swift中是没有‘A’这种字符表示方法的,更不用说用它去进行运算了,其次Character不能进行大小比较,只能进行想等或者不等的比较,这样一来在判断一个字符所在的区间上就遇到了很大的问题。

SwiftString提供了uft8uft16方法,返回值为UTF8View或者UFT16View,这是一个Array,使用for-in遍历他们可以输出他们的数字值,但是这个值也仅仅是能进行输出使用,他们不是Int也不能进行加减运算。不能进行运算在转换上就无能为力。单单从这里看来,Swift确实蛋疼,连这么一个小小的问题都不能搞定。

不过还好,SwiftCocoa做了兼容使得StringNSString可以无缝转化,在使用了NSString后,问题的处理就变得简单多了,在SwiftNSString使用一系列的unichar组成的,查看声明可以看到他其实就是UInt,那么他就可以进行运算,所以把String改成NSString完成这两个方法。即使这样,Swift不支持‘A’这种字符的特性,也使得我们必须自己把字符转化为数值来运算,使得程序的可读性很差,还就是Swift的内置类型不支持隐式转换,所以在类型不一致的地方都需要强制转换一下。

这两个方法的实现在文末的代码中有,这个代码虽然完成了功能,但是还有很多需要改进和优化的地方,其次在代码风格上也需要改一下,RaywenderlichSwift的代码风格就很不错,非常值得套用。

最后说一下,在iOS8UIAlertViewUIActionSheet被废除了,而引入的是UIAlertController,通过preferredStyle来确定类型,通过UIAlertAction来增加事件,然后通过presentViewController来显示出来,在使用上做到了统一,还是蛮方便的。

下面附上完全的代码,

(HexConverterViewController.m) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
//
//  ViewController.swift
//  HexConverter_swift
//
//  Created by taowang on 7/24/14.
//  Copyright (c) 2014 Meilishuo. All rights reserved.
//

import UIKit

class ViewController: UIViewController {

    @IBOutlet var beforeConvertTextField: UITextField
    @IBOutlet var afterConvertTextField: UITextField
    @IBOutlet var segmentControl: UISegmentedControl

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        self.segmentControl.addTarget(self, action: Selector("setTextFieldKeyboardType"), forControlEvents: UIControlEvents.ValueChanged)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func decimalConvertedFromHexdecimal(hexdecimal: NSString) -> NSString? {

        var sum: Int = 0
        for (var i: Int = 0; i < hexdecimal.length; i++) {
            var c: unichar = hexdecimal.characterAtIndex(i)

            var num: unichar = 0;
            if (c >= 65 && c <= 70) {
                num = c - 55;
            } else if (c >= 97 && c <= 102) {
                num = c - 87;
            } else if (c >= 48 && c <= 57) {
                num = c - 48;
            } else {
                let alert = UIAlertController(title: "错误", message: "你提供了非法字符", preferredStyle: .Alert)
                alert.addAction(UIAlertAction(title: "知道了", style: .Cancel, handler: nil))
                self.presentViewController(alert, animated: true, completion: nil)

                self.beforeConvertTextField.text = ""
                self.beforeConvertTextField.becomeFirstResponder()

                return nil
            }

            let tmp = Int(pow(16, CDouble(hexdecimal.length - i - 1)))

            sum = sum + Int(num) * tmp
        }

        return NSString(format: "%d", sum)
    }

    func hexdecimalConvertedFromDecimal(decimal: NSString) -> NSString? {

        var num: Int = decimal.integerValue;
        var result: NSMutableString = NSMutableString(capacity: 0);

        while (num > 0) {
            var tmp = num % 16;
            var c: unichar = 48;
            if (tmp > 9) {
            c = 97 + unichar(tmp - 10);
            } else {
                c = 48 + unichar(tmp);
            }
            let character: NSString = NSString(format:"%c", c)
            result.insertString(character, atIndex: 0)
            num /= 16;
        }

        return result;
    }

    func setTextFieldKeyboardType() {
        self.beforeConvertTextField.resignFirstResponder()
        if (self.segmentControl.selectedSegmentIndex == 0) {
            self.beforeConvertTextField.keyboardType = .ASCIICapable;
        } else {
            self.beforeConvertTextField.keyboardType = .NumberPad;
        }
        self.beforeConvertTextField.becomeFirstResponder();
    }

    @IBAction func endEditing(sender: AnyObject) {
        self.view.endEditing(true)
    }

    @IBAction func convertButtonPressed(sender: AnyObject) {
        if ("" == self.beforeConvertTextField.text)  {
            var alert = UIAlertController(title: "提示", message: "你还没有填写被转换数字", preferredStyle: .Alert)
            alert.addAction(UIAlertAction(title: "知道了", style: .Cancel, handler: nil))
            self.presentViewController(alert, animated: true, completion: nil)
            return
        }

        self.beforeConvertTextField.resignFirstResponder()
        if (0 == self.segmentControl.selectedSegmentIndex) {
            self.afterConvertTextField.text = self.decimalConvertedFromHexdecimal(self.beforeConvertTextField.text)
        } else {
            self.afterConvertTextField.text = self.hexdecimalConvertedFromDecimal(self.beforeConvertTextField.text)
        }
    }

}

Comments