类型转换 Objective-C 和 Swift
在 iOS 开发使用 Swift 时, 经常会遇到需要调用Objective-C
类方法的情况,苹果已经将几乎所有的Objective-C
的API都已经无缝的转接到了 Swift,同时一些特别的类型也做了桥接,桥接意味着可以随意进行转换。
1 2 3 4 5 6 7 8
| Let aString = (aString as NSString).lenght (anArray as NSArray).componentsJoinedByString(NSString) * Array 桥接到了 NSArray。对应的是AnyObject的数组。* * Dictionary 桥接到了 NSDictionary 对应的是 [NSObject:AnyObject] * Int, Float Double, Bool 都桥接到了 NSNumber (反过来不适用) * 如果需要从 NSNumber 对象中获取某个类型需要用 doubleValue,intValue 等。 */
|
利用这种括弧 + as
的方法可以直接调用Objective-C
的方法, 同时实现了自动的类型转换,比如上面的例子,lenght
是NSString
的方法, 我们可直接在一行代码中将String
转换成NSString
并调用其方法。
String Array
和Dictionary
都是结构体,而不是类,但他们仍然可以对应 AnyObject
,因为它们桥接到的NS
类版本都是类。
Dictionary
被桥接到了NSDictionary -> [NSObject:AnyObject]
。虽然Key值对应的并不是桥接的NSString
, 但NSString
继承自NSObject
.
typealias
我们可以使用 typealias 关键字为某个类型声明别名。比如想让某个类型有特别的意思。例如
1
| typealias AudioSample = Int
|
之后在代码中使用Int
类型的话就可以直接使用别名AudioSample
了。
operation
++ 或 –放在前后的区别。
1 2 3 4 5 6
| let prefix = ++start let postfix = start++
|
Property List
Property List
表面上可以看作是 AnyObject
, 它们是一组只有创建者才知道如何解释的数据,其包括的数据类型和CoreData
中支持的数据类型类似,同时可以用于泛型的数据结构
。
我们可以利用下列常用方法进行某些类型的存储:
1 2 3 4 5 6 7 8 9 10 11
| It can store/retrieve entire Property Lists by name (keys) … */ setObject(AnyObject, forKey: String) objectForKey(String) -> AnyObject? arrayForKey(String) -> Array<AnyObject>? It can also store/retrieve little pieces of data … */ setDouble(Double, forKey: String) doubleForKey(String) -> Double
|
Property List
其中的一个使用场景就是NSUserDefaults
,通常用来存储一些用户设置之类的小数据,因为性能问题,切记不要用来存储图片类的大数据。下面是使用 NSUserDefault
常用方法。
1 2 3 4 5 6
| 使用类方法 let defaults = NSUserDefaults.standardUserDefaults() 读或写 let plist: AnyObject = defaults.objectForKey(String) defaults.setObject(AnyObject, forKey: String)
|
你在任何地方做的改变都会自动保存,而下面的方法会强制保存,比如在调试的时候直接在Xcode终止模拟器时,App是不会触发自动保存的,可以适时插入synchronize
,进行强制保存。
1 2
| if !defaults.synchronize() {
|
CGRect
CGRect 在Swift 中是结构体,包括两个属性。
1 2 3 4 5
| struct CGRect { var origin: CGPoint var size: CGSize } let rect = CGRect(origin: aCGPoint, size: aCGRize)
|
CGRect 提供了很多便利的方法,帮助我们快速设置范围
UIView
我们在开发过程经常需要自定义某个视图,比如需要绘制某些形状到屏幕上,或者希望通过与UIButton、Slider 不同的方式,让某个视图能够响应用户的某种触摸事件。这时候,就需要我们设计自己的UIView子类。
我们通过重写 UIView 的 drawRect()方法,来实现在屏幕上的自定义绘制。
1
| override func drawRect(regionThatNeedsToBeDrawn: CGRect)
|
在drawRect()
方法中, 我们既可以使用更接近底层的 C-Like APICore Graphics
, 也可以使用面向对象的UIBezierPath类.
理所当然,这个方法会在视图初始化的时候即被调用,但当用户通过某个触摸事件更改了视图的某个属性,需要通知视图重新绘制时,不能直接调用子类的 drawRect
方法,而是通过调用下面的方法来通知iOS某个视图需要重新绘制,系统会在合适的时间,调用drawRect
。
1 2
| setNeedsDisplay() setNeedsDisplayInRect(regionThatNeedsToBeRedrawn: CGRect)
|
在 drawRect 方法中进行绘制代码编写的时候,可参考下列顺序.
1 2 3 4
| 1. 你需要拿到绘制的上下文`context`, 利用 `UIGraphicsGetCurrentContext()方法可以获得. 2. 创建即将绘制的路径 Path, 通过线条和弧线或者类似的东西 3. 设置绘制时的`attributes`, 比如:颜色,字体,textures, linwidths, linecaps. 等. 4. 最后描边并且填充之前创建的路径 Path
|
上面就是绘制的基本步骤, 不仅仅是绘制图片,文字也是如此,在知道字体的情况下,iOS 知道如何获得一个完美的路径来绘制漂亮的字母,并将其填充。
示例:
1 2
| let path = UIBezierPath()
|
如果需要绘制透明的颜色,需要将视图允许的属性设置成true,因为透明的系统资源
你可以利用 UIBezierPath 来画一些比较复杂的图形
1 2 3 4
| //圆角矩形 let rondRect = UIBezierPath(roundedRect: aCGRect, cornerRadius: aCGFloat) //椭圆 let oval = UIBezierPath(ovalInRect: aCGRect)
|
Clipping your drawing to a UIBezierPath’s path
你也可以剪切任意的 Path, 它意味着如果我设置好了,我有一个 Path, 我要剪切,如果我调用 addClip(), 那么在这之后的所有绘图操作只会影响到 Path 里面的部分.举个例子,比如你要在屏幕上画一张纸牌,纸牌有圆角的效果,所以你可以把纸牌画在一个大的矩形里面,然后剪切到一个圆角矩阵里,这样四个角就修圆了.
Hit Detection
碰撞测试.判断某个坐标点是不是在 path 中.
1 2 3
| func containsPoint(CGPoint) -> Bool // returns whether the point is inside the path The path must be closed. The winding rule can be set with userEvenOddFillRule property
|
#####Drawing Text
我们通常使用UIKit的UILabel将字符呈现在屏幕上,但你同样可以通过drawRect
进行字符的绘制。
我们需要用到 NSAttributedString 来描述字符的字体,颜色,大小,等等属性。
1 2 3 4
| let text = NSAttributedString(“hello”) text.drawAtPoint(aCGPoint) let textSize: CGSize = text.size
|
同时,NSAttributedString 还拥有一个可变类型,当需要动态的更改字符属性的时候使用。
1
| let mutableText = NSMutableAttributedString(“some string”)
|
注意 NSAttributedString 不是 String 或者 NSString,我们需要通过它的string
or mutableString
来获取它的字符串。
创建NSAttributedString之后,我们就可以为字符串添加属性了
1 2 3 4 5
| func setAttributes(attributes: Dictionary, range: NSRange) func addAttributes(attributes: Dictionary, range: NSRange) Warning! This is a pre-Swift API. NSRange is not a Range.And indexing into the string is using old-style indexing (not String.Index) */
|
这里可以展开讨论一下String.Index
字符的属性祖耀封装到字典中进行设置,我们常用到的属性包括:
1 2 3 4 5 6
| NSForegroundColorAttributeName : UIColor NSStrokeWidthAttributeName : CGFloat NSFontAttributeName : UIFont 更多的信息可以查看文档,在NSAttributedString(NSStringDrawing) 下。 */
|
对于字符属性最重要的就是字体,自 iOS7 之后,苹果推出了动态调整全局字体大小的方案,如果需要让自己的App支持系统级的调整字体大小,我们就需要使用系统推荐的字体,我们可以通过下面的方法获取适合排版的字体样式。
1 2 3 4 5 6 7 8 9 10
| Get preferred font for a given text style (e.g. body, etc.) using this UIFont type method … */ class func preferredFontForTextStyle(UIFontTextStyle) -> UIFont /** Some of the styles (see UIFontDescriptor documentation for more) … */ UIFontTextStyle.Headline UIFontTextStyle.Body UIFontTextStyle.Footnote
|
1 2 3 4 5 6 7 8 9
| These appear usually on things like buttons */ class func systemFontOfSize(pointSize: CGFloat) -> UIFont class func boldSystemFontOfSize(pointSize: CGFloat) -> UIFont /** Don’t use these for your user’s content. Use preferred fonts for that. 你可以通过查看文档的UIFont和UIFontDescriptor 了解更多信息,但用到的不会太多。 */
|
Drawing Image
和字符一样,通常我们需要在屏幕上呈现图片的时候会使用UIImageView,但是,你可能希望绘制某张图片到一个固定的范围,下面我们来看看如何在drawRect
中创建UIImage对象。
1 2 3 4 5
| let image: UIImage? = UIImage(named: “foo”) 添加 foo.jpg 到你项目中的 Images.xcassets */
|
你也可以将某个系统路径或者二进制数据作为UIImage的来源,图片的格式可以是:jpg
,png
,tiff
等。
1 2 3 4 5
| But we haven’t talked about getting at files in the file system … anyway …) */ let image: UIImage? = UIImage(contentsOfFile: aString) let image: UIImage? = UIImage(data: anNSData)
|
你还可以使用更底层的Core Graphics
创建图片,可从文档UIGraphicsBeginImageContext(CGSize) 中了解更详细的信息。
在创建UIImage之后,我们需要利用下面的方法进行屏幕中的定位和绘制。
1 2 3 4 5 6
| let image: UIImage = … image.drawAtPoint(aCGPoint) image.drawInRect(aCGRect) image.drawAsPatternInRect(aCGRect)
|
在绘制图片的时候,我们要考虑屏幕翻转带来的bounds
变化,默认情况下,bounds
改变后,View并不会重新绘制,其实UIView的contentMode
属性可以帮助我们控制这种情况。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| var contentMode: UIViewContentMode contentMode 属性的关联值很多,我们可以将他们分成三个类别 */ .Left .Right .Top .Botto .TopRight .BottomRight .BottomLeft .Center .ScaleToFill .ScaleAspectFill .ScaleAspectFit .Redraw
|
这些值我们不仅仅可以通过代码实现,在 Xcode 中的``也可以进行直接设置。
下面是重写drawRect
绘制的Demo:FaceView
Creat a custom UIView subclass to draw a face with a specified amount of “smallness”
未完待续。