Tag Archives: Objective-C

Objective-C中的Class(类类型),Selector(选择器SEL),函数指针(IMP)

看到了一篇牛文“Objective-C 2.0 with Cocoa Foundation— 5,Class类型,选择器Selector以及函数指针”,讲得十分精彩,忍不住把它的代码加上注释整理于此,以便日后查看。
个人体会:obj-C中的“Class类型变量”比c#中的Object基类还要灵活,可以用它生成任何类型的实例(但是它又不是NSObject)。而选择器SEL与函数指针IMP,如果非要跟c#扯上关系的话,这二个结合起来,就点类似c#中的反射+委托,可以根据一个方法名称字符串,直接调用方法。
“牛”的基类 Cattle.h
1
2
3
4
5
6
7
8
#import <Foundation/Foundation.h>
@interface Cattle : NSObject {
    int legsCount;
}
- (void)saySomething;
- (void)setLegsCount:(int) count;
@end
 Cattle.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#import "Cattle.h"
@implementation Cattle
-(void) saySomething
{
    NSLog(@"Hello, I am a cattle, I have %d legs.", legsCount);
}
-(void) setLegsCount:(int) count
{
    legsCount = count;
}
@end
子类“公牛” Bull.h
1
2
3
4
5
6
7
8
9
10
#import <Foundation/Foundation.h>
#import "Cattle.h"
@interface Bull : Cattle {
    NSString *skinColor;
}
- (void)saySomething;
- (NSString*) getSkinColor;
- (void) setSkinColor:(NSString *) color;
@end
Bull.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#import "Bull.h"
@implementation Bull
-(void) saySomething
{
    NSLog(@"Hello, I am a %@ bull, I have %d legs.", [self getSkinColor],legsCount);
}
-(NSString*) getSkinColor
{
    return skinColor;
}
- (void) setSkinColor:(NSString *) color
{
    skinColor = color;
}
@end
代理类DoProxy.h (关键的代码都在这里)
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
#import <Foundation/Foundation.h>
//定义几个字符串常量
#define SET_SKIN_COLOR @"setSkinColor:"
#define BULL_CLASS @"Bull"
#define CATTLE_CLASS @"Cattle"
@interface DoProxy : NSObject {
    BOOL notFirstRun;
    
    id cattle[3];
    //定义二个选择器
    SEL say;
    SEL skin;
    
    //定义一个函数指针(传统C语言的处理方式)
    void(*setSkinColor_Func)(id,SEL,NSString*);
    
    //定义一个IMP方式的函数指针(obj-C中推荐的方式)
    IMP say_Func;
    
    //定义一个类
    Class bullClass;
}
-(void) doWithCattleId:(id) aCattle colorParam:(NSString*) color;
-(void) setAllIVars;
-(void) SELFuncs;
-(void) functionPointers;
@end
DoProxy.m
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
#import "DoProxy.h"
#import "Cattle.h"
#import "Bull.h"
@implementation DoProxy
//初始化所有变量
- (void) setAllIVars
{  
    cattle[0] = [Cattle new];
    
    bullClass = NSClassFromString(BULL_CLASS);
    //即cattle[1],cattle[2]都是Bull类的实例
    cattle[1] = [bullClass new];
    cattle[2] = [bullClass new];
    
    say = @selector(saySomething);
    skin = NSSelectorFromString(SET_SKIN_COLOR);
}
//初始化id
- (void) doWithCattleId:(id) aCattle colorParam:(NSString*) color
{
    //第一次运行的时候
    if(notFirstRun == NO)
    {
        NSString *myName = NSStringFromSelector(_cmd);//取得当前正在执行的方法的名字
        NSLog(@"Running in the method of %@", myName);
        notFirstRun = YES;//修改初次运行标志位
    }
    
    NSString *cattleParamClassName = [aCattle className];//取得aCattle的"类名称"
    
    //如果aCattle是Bull或Cattle类的实例
    if([cattleParamClassName isEqualToString:BULL_CLASS] || [cattleParamClassName isEqualToString:CATTLE_CLASS])
    {
        [aCattle setLegsCount:4];//设置牛的4条腿
        if([aCattle respondsToSelector:skin])//如果aCattle对应的是类中,有定义方法"setSkinColor"
        {
            [aCattle performSelector:skin withObject:color];//则调用setSkinColor方法
        }
        else
        {
            NSLog(@"Hi, I am a %@, have not setSkinColor!", cattleParamClassName);//否则输出相应的提示信息
        }
        [aCattle performSelector:say];//最后执行saySomething方法(这二个方法在Bull与Cattle类中都有,所以肯定能运行)
    }
    else //如果aCattle即不是Bull类也不是Cattle类的实例
    {
        NSString *yourClassName = [aCattle className];
        NSLog(@"Hi, you are a %@, but I like cattle or bull!", yourClassName);//显示这个"异类"的相关信息
    }
}
//初始化选择器以及相应函数
- (void) SELFuncs
{
    [self doWithCattleId:cattle[0] colorParam:@"brown"];
    [self doWithCattleId:cattle[1] colorParam:@"red"];
    [self doWithCattleId:cattle[2] colorParam:@"black"];
    [self doWithCattleId:self colorParam:@"haha"];//这里故意传入一个异类self(即DoProxy本身),DoProxy当然不是Bull或Cattle
}
//函数指针测试
- (void) functionPointers
{
    //取得函数指针的第一种方式
    setSkinColor_Func=(void (*)(id, SEL, NSString*)) [cattle[1] methodForSelector:skin];
    //上面的语句其实等效于下面这种方法
    //IMP setSkinColor_Func = [cattle[1] methodForSelector:skin];
    
    //用第二种方法取得saySomething的函数指针
    say_Func = [cattle[1] methodForSelector:say];
    
    //用函数指针的形式调用setSkinColor
    setSkinColor_Func(cattle[1],skin,@"verbose");
    
    NSLog(@"Running as a function pointer will be more efficiency!");
    
    //调用saySomething方法
    say_Func(cattle[1],say);
}
@end
测试主函数main()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#import <Foundation/Foundation.h>
#import "DoProxy.h"
int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    DoProxy *doProxy = [DoProxy new];
    
    [doProxy setAllIVars];
    [doProxy SELFuncs];
    [doProxy functionPointers];
    
    [doProxy release];
    [pool drain];
    return 0;
}

运行结果:

2011-02-28 21:40:33.240 HelloSelector[630:a0f] Running in the method of doWithCattleId:colorParam:
2011-02-28 21:40:33.245 HelloSelector[630:a0f] Hi, I am a Cattle, have not setSkinColor!
2011-02-28 21:40:33.247 HelloSelector[630:a0f] Hello, I am a cattle, I have 4 legs.
2011-02-28 21:40:33.248 HelloSelector[630:a0f] Hello, I am a red bull, I have 4 legs.
2011-02-28 21:40:33.250 HelloSelector[630:a0f] Hello, I am a black bull, I have 4 legs.
2011-02-28 21:40:33.251 HelloSelector[630:a0f] Hi, you are a DoProxy, but I like cattle or bull!
2011-02-28 21:40:33.252 HelloSelector[630:a0f] Running as a function pointer will be more efficiency!
2011-02-28 21:40:33.254 HelloSelector[630:a0f] Hello, I am a verbose bull, I have 4 legs.

作者:菩提树下的杨过
出处:http://yjmyzz.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

Objective-c的动态调用函数的方法

最近在看关于selector的资料,感觉很好玩。

首先我能理解什么叫selector已经不容易了,查阅了很多资料。
其次是要动态调用,首先网上找到的方法是,这样的用法:

-(void)traceThem:(int)a traceThem2:(int)b{

NSLog(@”hello:%d 你好%d”,a,b);

}

[self performSelector:@selector(traceThem:traceThem2:) withObject:(id)1 withObject:(id)2];

上面代码的意思要调用函数名为traceThem:traceThem2:的函数,参数分别是1,2

(OC就叫发消息,它的函数说法是有一条traceThem:traceThem2:的消息,reciver是self,其实编译的时候还不是自己改成调用函数的概念。);

performSelector这样的调用函数方法,最多只能支持2个参数,你可以把参数放到NSDictionary传递。

搞到百度到的一大堆blog文都是自己写了一大段代码来支持performSelector多个参数的调用。。。

其实还有个好方法objc_msgSend:

objc_msgSend(self,@selector(traceThem:traceThem2:traceThme3:),参数1,参数2,参数3);

但是动态调用,就是要求@selector()的参数能动态输入,例如是配置到一个配置表中的字符串(NSString),方法如下:

SEL function = NSSelectorFromString(@”traceThem:traceThem2:traceThem3:”);

objc_msgSend(self,function,1,2,3);

BTW:

由于objc_msgSend是运行时的方法,所以要加入头文件,用open quickly可帮到大忙,如下:

,即需要的头文件:#import <objc/message.h>

 

objective-c的动态调用函数的方法 - Sylar_Lin - 低调做人高调做事

Using Swift with Cocoa and OC与Cocoa和OC一起使用Swift

Swift系列文章由CocoaChina翻译小组翻译自苹果的官方文档,本篇译者:@Creolophus,敬请勘误!

互用性是让Swift和Objective-C相接合的一种特性,使你能够在一种语言编写的文件中访问和使用另一种语言编写的代码。当你准备开始把Swift融入到你的开发流程中时,你应该懂得如何利用互用性来重新定义并提高你写Cocoa应用的方式。互用性很重要的一点就是当你在写Swift代码时使用Objective-C的API接口。当你导入一个Objective-C框架后,你可以使用原生的Swift语法实例化它的Class并且与之交互。

初始化(Initialization)

为了使用Swift实例化Objective-C的Class,你应该使用Swift语法调用它的一个初始化器。当Objective-C的init方法变化到Swift,它们用Swift初始化语法呈现。”init”前缀被截断当作一个关键字,用来表明该方法是初始化方法。那些以“initWith”开头的init方法,“With”也会被去除。从“init”或者“initWith”中分离出来的这部分方法名首字母变成小写,并且被当做是第一个参数的参数名。其余的每一部分方法名依次变为参数名。这些方法名都在圆括号中被调用。

举个例子,你在使用Objective-C时会这样做:

UITableView *myTableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped];

在Swift中,你应该这样做:

let myTableView: UITableView = UITableView(frame: CGRectZero, style: .Grouped)

你不需要调用alloc,Swift能替你处理。注意,当使用Swift风格的初始化函数的时候,”init”不会出现。

你可以在初始化时显式地声明对象的类型,或者也可以忽略它,Swift的类型接口能够正确判断对象的类型。

//Swift
let myTextField = UITextField(frame: CGRect(0.0, 0.0, 200.0, 40.0))

这里的UITableView和UITextField对象和你在Objective-C中使用的具有相同的功能。你可以用样的方式使用他们,包括访问属性或者调用各自的类中定义的方法。

为了统一和简易,Objective-C的工厂方法也在Swift中映射为方便的初始化方法。这种映射能够让他们使用同样简洁明了的初始化方法。例如,在Objective-C中你可能会像下面这样调用一个工厂方法:

//Objective-C
UIColor *color = [UIColor colorWithRed:0.5 green:0.0 blue:0.5 alpha:1.0];

在Swift中,你应该这样做:

//Swift
let color = UIColor(red: 0.5, green: 0.0, blue: 0.5, alpha: 1.0)

访问属性(Accessing Properties)

在Swift中访问和设置Objective-C对象的属性时,使用点语法

///Swift
myTextField.textColor = UIColor.darkGrayColor()
myTextField.text = “Hello world”
if myTextField.editing {
myTextField.editing = false
}

当getting或setting属性时,直接使用属性名称,不需要附加圆括号。注意,darkGrayColor后面附加了一对圆括号,这是因为darkGrayColor是UIColor的一个类方法,不是一个属性。 在Objective-C中,一个有返回值的无参数方法可以被作为一个隐式的访问函数(implicit getter),并且可以与访问器使用同样的方法调用。但在Swift中不再能够这样做了,只有使用Objective-C中@property语法编写的属性才能被作为属性引入。详细请参看Working with Methods。

使用方法(Working with Methods)

在Swift中调用Objective-C方法时,使用点语法。 当Objective-C方法转换到Swift时,Objective-C的selector的第一部分将会成为基本方法名并出现在圆括号的前面,而第一个参数将直接在括号中出现,并且没有参数名,而剩下的参数名与参数则一一对应地填入圆括号中。

举个例子,你在使用Objective-C时会这样做:

//Objective-C
[myTableView insertSubview:mySubview atIndex:2];

在Swift中,你应该这样做:

//Swift
myTableView.insertSubview(mySubview, atIndex: 2)

如果你调用一个无参方法,仍必须在方法名后面加上一对圆括号

//Swift
myTableView.layoutIfNeeded()

id 兼容性(id Compatibility)

Swift包含一个叫做AnyObject的协议类型,用以表示任意类型的对象,就像Objective-C中的id一样。AnyObject协议允许你编写类型安全的Swift代码,同时维持无类型对象的灵活性。因为AnyObject协议也保证了这种安全,Swift将id对象导入为AnyObject。

举个例子,跟id一样,你可以为AnyObject类型的对象分配任何其他类型的对象,你也同样可以为它重新分配其他类型的对象。

//Swift
var myObject: AnyObject = UITableViewCell()
myObject = NSDate()

你也可以在调用Objective-C方法或者访问属性时不将它转换为具体类的类型。这包括了Objcive-C中标记为@objc的方法。

//Swift
let futureDate = myObject.dateByAddingTimeInterval(10)
let timeSinceNow = myObject.timeIntervalSinceNow

然而,由于直到运行时才知道AnyObject的对象类型,所以有可能在不经意间写出不安全代码。另外,与Objective-C不同的是,如果你调用的方法或者访问的属性没有经AnyObject对象声明,运行时将会报错。比如下面的代码在运行时将会报出一个未被识别的selector error:

//Swift
myObject.characterAtIndex(5)
// crash, myObject does’t respond to that method

但是,你可以通过Swift的optinals特性来排除这个Objective-C中常见的错误。当你用AnyObject对象调用一个Objective-C方法时,这次调用将会变成一次隐式展开optional(implicitly unwrapped optional)的行为。你可以通过optional特性来决定AnyObject类型的对象是否调用该方法,同样的,你可以把这种特性应用在属性上。

举个例子,在下面的代码中,第一和第二行代码将不会被执行,因为length属性和characterAtIndex:方法不存在于NSDate对象中。myLength常量会被推测成可选的Int类型并且被赋值为nil。同样你可以使用if-let声明来有条件的展开这个方法的返回结果,从而判断对象是否能执行这个方法。就像第三行做的一样。

//Swift
let myLength = myObject.length?
let myChar = myObject.characterAtIndex?(5)
if let fifthCharacter = myObject.characterAtIndex(5) {
println(“Found \(fifthCharacter) at index 5”)
}

对于Swift中的强制类型转换,从AnyObject转换为更特殊的对象类型并不会保证成功,所以它会返回一个可选值。而你需通过检查该值的类型来确认转换是否成功。

//Swift
let userDefaults = NSUserDefaults.standardUserDefaults()
let lastRefreshDate: AnyObject? = userDefaults.objectForKey(“LastRefreshDate”)
if let date = lastRefreshDate as? NSDate {
println(“\(date.timeIntervalSinceReferenceDate)”)
}

当然,如果你能确定这个对象的类型(并且确定不是nil),你可以添加as操作符强制调用。

//Swift
let myDate = lastRefreshDate as NSDate
let timeInterval = myDate.timeIntervalSinceReferenceDate

使用nil(Working with nil)

在Objective-C中,对象的引用可以是值为NULL的原始指针(同样也是Objective-C中的nil)。而在Swift中,所有的值–包括结构体与对象的引用都被保证为非空。作为替代,你将这个可以为空的值包装为optional type。当你需要宣告值为空时,你需要使用nil。你可以在Optionals中了解更多。

因为Objective-C不能保证一个对象是non-nil的,所以Swift在引入Objective-C的API的时候,确保了所有函数的返回类型与参数类型都是optional。在使用Objective-C的API之前,你应该检查并保证该值非空。在某些情况下,你可能绝对确认某些Objective-C方法或者属性永远不应该返回一个nil的对象引用。为了让对象在这种情况下更加易用,Swift使用implicitly unwrapped optionals方法引入对象,implicitly unwrapped optionals 包含optional类型的所有安全特性。此外,你可以直接访问对象的值而无需检查nil或者自己展开它。当你访问这种类型的变量时,implicitly unwrapped optional 首先检查这个对象的值是否不存在,如果值不存在,那它将会抛出一个运行时错误。因此,你通常需要检查和展开一个implicitly unwrapped optional,除非你确定值不会为空。

扩展(Extensions)

Swift的扩展和Objective-C的类别(Category)相似。扩展为原有的类、结构和枚举丰富了功能,包括在Objective-C中定义过的。你可以为系统的框架或者你自己的类型定义扩展。简单要导入合适的模块并且保证你在Objective-C中使用的类、结构或枚举拥有相同的名字。举个例子,你可以扩展UIBezierPath类通过正三角形来创建一个简单的Bézier路径,这个方法只需提供三角形的边长与起点。

//Swift
extension UIBezierPath {
convenience init(triangleSideLength: Float, origin: CGPoint) {
self.init()
let squareRoot = Float(sqrt(3))
let altitude = (squareRoot * triangleSideLength) / 2
moveToPoint(origin)
addLineToPoint(CGPoint(triangleSideLength, origin.x))
addLineToPoint(CGPoint(triangleSideLength / 2, altitude))
closePath()
}
}

你也可以使用扩展来增加属性(包括类与静态属性)。然而,这些属性必须是通过计算才能获取的,扩展不会为类,结构体以及枚举添加存储属性。下面这个例子为CGRect类增加了一个经计算过的area属性。

//Swift
extension CGRect {
var area: CGFloat {
return width * height
}
}
let rect = CGRect(x: 0.0, y: 0.0, width: 10.0, height: 50.0)
let area = rect.area
// area: CGFloat = 500.0

你同样可以使用扩展来为类添加协议而无需对它进行子类化。如果这个协议是在Swift中被定义的,你可以添加comformance到它的结构或枚举中,无论它们是在Objective-C或在Swift中被定义。你不能使用扩展来覆盖Objective-C类型中存在的方法与属性。

闭包(Closures)

Objective-C中的blocks会被自动导入为Swift中的闭包。例如,下面是一个Objective-C 中的block变量:

//Objective-C
void (^completionBlock)(NSData *, NSError *) = ^(NSData *data, NSError *error) {/* … */}

而它在Swift中的形式为:

//Swift
let completionBlock: (NSData, NSError) -> Void = {data, error in /* … */}

Swift的闭包与Objective-C中的blocks能够兼容,所以你可以把一个Swift闭包传递给一个把block作为参数的Objective-C方法。Swift闭包与函数具有相同的类型,所以你甚至可以传递Swift函数的名字。闭包与blocks语义上想通,但在一个地方不同:变量是可以直接改变的,但不是像block那样会拷贝变量。换句话说,Swift中变量的默认行为与Objective-C中__block变量一致。

对象比较(Object Comparison)

如果你在Swift比较两个对象,那么会有两种不同的类型的比较。第一个equality 相等(==)用于比较对象的内容,第二个identity 恒等(===)用以决定常量或者变量是否引用同一个对象实例。在Swift中比较Swift和Objective-C对象使用==和===运算符。

Swift为源自NSObject类的对象提供了默认的==实现。在该运算符的实现中,Swift调用了NSObject类的isEqual:方法。NSObject类仅实现identity (===)比较,所以你应该在源自NSObject的类中实现你自己的isEqual:方法。

由于你可以把Swift对象(包括不是源自NSObject的对象)传递给Objective-C API,所以如果你想要Objective-C API比较对象的内容时,你应该实现isEqual:方法。作为实现类相等的一部分,要确保根据Object comparison中的规则实现hash属性。更进一步说,如果你想要在字典中把类用作键,那么也要遵照Hashable协议,并实现hashValue属性。

Swift类型兼容性(Swift Type Compatibility)

当你定义了一个继承自NSObject或者其他Objective-C 类的Swift类,这些类会自动兼容Objective-C。所有的步骤都有Swift编译器自动完成,如果你从未在Objective-C代码中导入Swift 类,你也不需要担心类型适配问题。另外一种情况,如果你的Swift类并不来源自Objectve-C类,而且你希望能在Objecive-C的代码中使用它,你可以使用下面描述的@objc属性。

@objc可以让你的Swift API在Objective-C和Objective-C runtime中使用。换句话说,你可以在任何Swift方法、类、属性前添加@objc,来使得他们可以在Objective-C代码中使用。如果你的类继承自Objective-C,编译器会自动帮助你完成这一步。编译器还会在类的所有方法和属性前加@objc,如果这个类自己前面加上了@objc关键字。当你使用@IBOutlet,@IBAction,或者是@NSManaged属性时,@objc也会添加在前面。当你使用selector实现target-action设计模式时,这个属性也会非常有用,例如,NSTimer或者UIButton。

当你在Objective-C中使用Swift API,编译器基本对语句做直接的翻译。例如,Swift API func playSong(name: String)(name:String)在Objective-C会被解释为- (void)playSong:(NSString *)name。然而,有一个例外:当在Objective-C中使用Swift的初始化函数,编译器会在方法前添加”initWith”,并且将原初始化函数的第一个参数首字母大写。

例如,这个Swift初始化函数init (songName: String, artist: String将被翻译为- (instancetype)initWithSongName:(NSString*)songName artist:(NSString *)artist 。 Swift同时也提供了一个@objc关键字的变体,允许你为Objective-C中的符号指定名称。例如,如果你的Swift 类的名字包含Objecytive-C中不支持的字符,你就可以为Objective-C提供一个可供替代的名字。如果你给Swift函数提供一个Objcetiv-C名字,请使用Objective-C selector syntax。要记得为带参数的函数添加(:)

//Swift
@objc(Squirrel)
class Белка {
@objc(initWithName:)
init (имя: String) { /*…*/ }
@objc(hideNuts:inTree:)
func прячьОрехи(Int, вДереве: Дерево) { /*…*/ }
}

当你在Swift类中使用@objc(<#name#>)属性,这个类可以不需要命名空间即可在Objective-C中使用。这个属性在你迁徙Objecive-C代码到Swift时同样也非常有用。由于归档过的对象存贮了类的名字,你应该使用@objc(<#name#>)来指定和Objective-C类一样的名字,这样旧的归档可以在新Swift类中恢复。

Objective-C选择器(Selectors)

Objective-Cselector是指向一个Objective-C方法名的类型。在Swift中,Objective-C selector被Selector结构体替代。你可以通过字符串字面量创建一个选择器,比如let mySelector: Selector =”tappedButton:”。因为字符串字面量能够自动转换为选择器,所以你可以把字符串字面量直接传递给任何接受选择器的方法。

//Swift
import UIKit
class MyViewController: UIViewController {
let myButton = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 50))

init(nibName nibNameOrNil: String!, bundle nibBundleOrNil: NSBundle!) {
super.init(nibName: nibName, bundle: nibBundle)
myButton.targetForAction(“tappedButton:”, withSender: self)
}

func tappedButton(sender: UIButton!) {
println(“tapped button”)
}
}

注意:performSelector:方法和相关的调用选择器的方法没有导入到Swift中,因为它们是不安全的。

如果你的Swift类继承自Objective-C的类,那么该类的所有方法和属性都可以用作Objective-C的选择器。另外,如果你的Swift类不是继承自Objective-C,如果你想要当选择器来使用你就需要在前面添加@objc关键字,详情请看Swift Type Compatibility。

Swift与Objective-C API交互(三)

Swift类型兼容性

定义一个继承自NSObject或者其他Objective-C的类,它自动与Objective-C兼容。如果你不需要将Swift对象导入Objective-C代码的话,没必要关注类型的兼容性。但是如果在Swift中定义的类不是Objective-C类的子类,在Objective-C中使用的时候,需要用@objc进行说明。

@objc使得Swift的API可以在Objective-C和它的运行时中使用。当使用@IBOutlet@IBAction或者@NSManaged等属性时,自动添加@objc属性。

@objc还可以用来指定Swift中的属性或方法在Objective-C中的名字,比如Swift支持Unicode名字,包括使用中文等Objective-C不兼容的字符。还有给Swift中定义的函数指定一个Selectorde名字。

@objc(Squirrel)
class 长沙戴维营教育 {
    @objc(hideNuts:inTree:)
    func 欢迎光临(Int, 姓名: String) {
        /* ... */
    }
}

@objc(<#name#>)属性作用在Swift的类上时,这个类在Objective-C的使用不受命名空间的限制。同样,在Swift中解归档Objective-C归档的对象时,由于归档对象中存放有类名,因此需要在Swift中用@objc<#name>说明Objective-C的类名。

Objective-C选择器(Selector)

Objective-C的选择器是方法的一个引用。在Swift中对应的是Selector结构体。使用字符串字面量可以构建一个选择器对象,如let mySelector: Selector = "tappedButton:"。由于字符串字面常量可以自动转换为选择器对象,因此可以在任何需要传递选择器的地方使用字符串字面常量。

import UIKit
class MyViewController: UIViewController {
    let myButton = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 50))

    init(nibName nibNameOrNil: String!, bundle nibBundleOrNil: NSBundle!)
    {
        super.init(nibName: nibName, bundle: nibBundle)
        myButton.targetForAction("tappedButton:", withSender: self)
    }

    func tappedButton(sender: UIButton!) {
        println("tapped button")
    }
}
提示
performSelector:以及相关的调用选择器的方法没有被引入到Swfit中来,因为它们不是完全安全的。

如果Swift类继承自Objective-C的类,则它里面的方法和属性都能够作为Objective-C的选择器使用。而如果不是Objective-C的子类,需要使用@objc属性修饰,这个在前面的Swift类型兼容性中有描述。

Swift与Objective-C API交互(二)

兼容id类型

Swift包含一个叫AnyObject的协议,与Objective-C中的id类似,可以表示任意类型的对象。AnyObject协议允许你在利用无类型对象的灵活性的同时保持类型安全。
你可以给AnyObject类型的变量赋任意的值:

var myObject: AnyObject = NSData()

可以直接方法AnyObject类型对象的任意属性和方法,而不需要进行强制类型转换。

let dateDescription = myObject.description
let timeSinceNow = myObject.timeIntervalSinceNow

由于AnyObject类型的变量的类型需要到运行时才能确定,因此可能会导致不安全的代码。特别是你可以访问一个不存在的属性或者方法,它只是在运行时报错。

myObject.characterAtIndex(5)
//crash, myObject doesn't respond to that method

在进行类型转换的时候,不一定转换成功,因此Swift返回的是一个Optional值。你可以检查是否转换成功。

let userDefaults = NSUserDefaults.standardUserDefaults()
let lastRefreshDate: AnyObject? = userDefault.objectForKey("LastRefreshDate")
if let date = lastRefreshDate as? NSDate {
    println("\(date.timeIntervalSinceReferenceDate)")
}

如果你能够确定对象的类型,并且不为nil,可以使用as操作符进行强制转换。

let myDate = lastRefreshDate as NSDate
let timeInterval = myDate.timeIntervalSinceReferenceDate

nil对象

Objective-C中使用nil来表示引用一个空对象(null)。Swift中所有的值都不会为nil。如果需要表示一个缺失的值,可以使用Optional。

由于Objective-C不能确保所有值都非空,因此Swift将Objective-C中引入的方法的参数和返回值都用Optional表示。在使用Objective-C对象之前,应该检查它们是否存在。

扩展

Swift的扩展与Objective-C的类别有点类似。扩展能够为已有类、结构体、枚举等增加行为。

下面是给UIBezierPath添加扩展:

extension UIBezierPath {
    class func bezierPathWithTriangle(length: Float, origin: CGPoint) -> UIBezierPath {
        let squareRoot = Float(sqrt(3))
        let altitude = (squareRoot * length) / 2
        let myPath = UIBezierPath()

        myPath.moveToPoint(orgin)
        myPath.addLineToPoint(CGPoint(length, origin.x))
        myPath.addLineToPoint(CGPoint(length / 2, altitude))
        myPath.closePath()

        return myPath
    }
}

可以使用扩展增加属性(包括类属性或静态属性)。不过这些属性只能是通过计算得来,而不能进行存储。下面给CGRect添加一个area属性:

extension CGRect {
    var area: CGFloat {
        return width * height
    }
}

let rect = CGRect(x: 0.0, y: 0.0, width: 10.0, height: 50.0)
let area = rect.area
//area: CGFloat = 500.0

使用扩展可以在不创建子类的情况下让现有的类响应某个协议。需要注意的是,扩展不能覆盖已有的方法和属性。

闭包

Objective-C中的Block 被自动导入为Swift的闭包。例如:

void (^completionBlock)(NSData *, NSError *) = ^(NSData *data, NSError *error) {
    /* ... */
}

在Swift 中对应为:

let completionBlock: (NSData, NSError) -> void = {
    data, error in /* ... */
}

Swift的闭包和Objective-C中的Block是兼容的,可以在Swift中给Objective-C的方法传递闭包来代替Block对象。

闭包和Block对象有一点不同,里面的变量是可变的,也就是说与__block修饰的变量行为相同。

对象比较

Swift中有两种对象比较的方式。第一种是相等(==(equality),用来比较两个对象的内容是否相同。第二种是恒等(===(identity),比较两个变量或者常量是否引用同一个对象。

NSObject只能比较是否引用了同一个对象(恒等),如果要比较内容是否相同,应该实现isEqual:方法。

Swift与Objective-C API交互(一)

Swift和Objective-C可以进行互操作,也就是说可以在Objective-C项目中使用Swift代码,反过来也可以。当然,这种互操作之间最重要的是可以在Swift中调用Objective-C的接口,毕竟目前绝大部分接口都是通过Objective-C提供的。

初始化

在Swift中实例化一个Objective-C的类时,可以用Swift语法调用它的一个初始化器。Objective-C的初始化方法被分割成关键字。例如“initWith”变成“init”,而剩下的部分作为方法的参数名。

Objective-C的代码:

UITableView *myTableView = [[UITableView alloc] initWithFrame: CGRectZero style: UITableViewStyleGrouped];

对应的Swift代码为:

let myTableView: UITableView = UITableView(frame: CGRectZero, style: .Grouped)

在Swift中不需要调用alloc方法,它会自动处理对象的创建功能。注意:Swift不会显式的调用init方法。

定义变量或者常量的时候,可以省略它的类型,Swift会自动识别。

let myTextField = UITextField(frame: CGRect(0.0, 0.0, 200.0, 40.0))

为了方便起见,Objective-C的工厂方法被映射为Swift中的初始化器。例如:

UIColor *color = [UIColor colorWithRed: 0.5 green: 0.0 blue: 0.5 alpha: 1.0];

转换为Swift:

let color = UIColor(red: 0.5, green: 0.0, blue: 0.5, alpha: 1.0)

属性访问

在Objective-C和Swift中访问属性都是使用点操作符。

myTextField.textColor = UIColor.darkGrayColor()
myTextField.text = "Hello world"
if myTextField.editing {
    myTextField.editing = false
}

访问和设置属性的时候不需要使用圆括号,上面darkGrayColor之所以有括号,是因为调用的是UIColor的类方法,而不是属性。

Objective-C中不需要参数并且有一个返回值的方法,可以被当作隐含的获取方法(getter),从而使用点操作符。但是在Swift中点操作符只能访问Objective-C中使用@property定义的属性。

方法调用

在Swift中使用点操作符调用Objective-C中的方法。

Objective-C的方法在Swift中调用的时候,它的第一部分成为Swift的基本方法出现在括号之前。然后函数的第一个参数没有名字,剩下的部分作为Swift函数对应的参数名称。
Objective-C语法:

[myTableView insertSubview: mySubview atIndex: 2];

Swift代码:

myTableView.insertSubview(mySubview atIndex: 2)

调用无参的方法:

myTableView.layoutIfNeeded()

call OC’s function in swift,在swift中调用OC函数

Hi, here is a demo writed by HunkSmile on github. It shows how to call Objective-C’s function in .swift file. The url is below:

https://github.com/HunkSmile/Swift

嗨,大家好,github上有个叫 HunkSmile的家伙,已经写了个例子,展示如何在swift中调用之前用OC写的函数。厉害吧,请参加上面的网址。嘿嘿,他还写下:

Write The Code, Change The World

牛逼,先向他致敬一下。

苹果发布编程swift语言全面优于Objective-C语言

苹果iPhone6编程语言Swift发布:全面优于Objective-C语言

网易6月3日消息 Swift语言一经发布就占据了各大开发者的眼球,早上刷微信朋友圈,发现漫天遍地都是招聘Swift语言的程序员,看来苹果iPhone6的这个新语言非常受欢迎。

苹果公司在美国旧金山召开2014年度全球开发者大会。在全球开发者大会之前,就有预测称此次苹果会有一些硬件产品亮相,甚至是iWatch智能手表、iPhone 6,因为健康管理应用HealthKit铁定发布。实际上,开场库克所提到的两件事均与硬件无关,分别是iOS 8与Mac OS X两部分,除此之外还发布了全新编程语言Swift。

在本届WWDC全球开发者大会接近尾声时,苹果公司专门针对开发人员公布全新的Swift编程语言以及新版的Xcode,苹果公司称其拥有“快速、现代、安全、互动”等特性,并且要全面优于Objective-C语言。“在过去的20年里,我们只支持Objective-C。”软件工程副总裁克雷格·费德里奇在台上表示,而未来苹果开发者平台将支持这款全新的Swift编程语言。

Xcode目前已有1400万次下载量,而全新的变成语言Swift改变了Obejective-C复杂的语法,并保留了Smalltalk的动态特性,简而言之就是敏捷易用,大家都说苹果的生态圈要由于Google,现在苹果又进一步完善了开发生态圈。相信日后又有更多优秀的App要与大家见面了,我们都知道软件也是支撑苹果的又一根基,不过今天来看期待硬件发布的朋友恐怕就要失望了。

早上一打开微信就发现朋友圈里有人写到“急招iOS工程师,要求Swift语言,开发经验一天以上”。基本上,今天不发Swift相关朋友圈的程序猿都不好意思说自己编程。许多非程序猿的朋友便好奇到,Swift到底是什么?

事实上,Swift是苹果新发布的编程语言,可以用来编写iOS和OS X端的应用。而让它备受关注的,则是其简洁的语法和效果实时预览的功能。