深入探索NSPredicate与不同语言过渡到Objective - C的要点
1. NSPredicate的基础及应用
NSPredicate在Objective - C中是一个强大的工具,用于过滤对象。例如,我们可以使用它来找出两个数组的交集。以下是一个示例代码:
NSArray *names1 = [NSArray arrayWithObjects:
@"Herbie", @"Badger", @"Judge", @"Elvis", nil];
NSArray *names2 = [NSArray arrayWithObjects:
@"Judge", @"Paper Car", @"Badger", @"Phoenix", nil];
NSPredicate *predicate = [NSPredicate predicateWithFormat: @"SELF IN %@", names1];
NSArray *results = [names2 filteredArrayUsingPredicate: predicate];
NSLog (@"%@", results);
运行这段代码,输出结果为:
(
Judge,
Badger
)
其工作原理是,谓词包含了第一个数组的内容,类似于
SELF IN {"Herbie", "Badger", "Judge", "Elvis"}
。然后用这个谓词过滤第二个数组,同时存在于两个数组中的字符串会使
SELF IN
子句为真,从而被包含在结果数组中。只存在于第二个数组中的对象会被丢弃,只存在于第一个数组中的字符串则不会出现在结果中。
2. 字符串操作相关的谓词运算符
除了基本的过滤,NSPredicate还提供了一些特定于字符串的运算符,如下表所示:
| 运算符 | 含义 |
| ---- | ---- |
| BEGINSWITH | 检查一个字符串是否以另一个字符串开头 |
| ENDSWITH | 检查一个字符串是否以另一个字符串结尾 |
| CONTAINS | 检查一个字符串是否包含在另一个字符串中 |
使用这些运算符可以实现一些有趣的匹配,例如:
-
"name BEGINSWITH 'Bad'"
可以匹配 “Badger”。
-
"name ENDSWITH 'vis'"
可以匹配 “Elvis”。
-
"name CONTAINS udg"
可以匹配 “Judge”。
需要注意的是,这些匹配是区分大小写和重音符号的。如果我们想忽略大小写和重音符号,可以使用
[c]
、
[d]
或
[cd]
修饰符。例如,
"name BEGINSWITH[cd] 'HERB'"
可以匹配 “Herbie”。
另外,当简单的开头、结尾或包含匹配不够强大时,我们可以使用
LIKE
运算符。在
LIKE
运算符中,问号
?
匹配一个字符,星号
*
匹配任意数量的字符。例如:
-
"name LIKE '*er*'"
可以匹配任何中间包含 “er” 的名字,这与
CONTAINS
等效。
-
"name LIKE '???er*'"
可以匹配 “Paper Car”,但不能匹配 “Badger”。
LIKE
运算符也支持
[cd]
修饰符来忽略大小写和重音符号。如果需要使用正则表达式,可以使用
MATCHES
运算符,但要注意正则表达式虽然强大,但计算成本较高,建议先使用基本的字符串运算符和比较运算符,再使用
MATCHES
以提高速度。
3. 从其他语言过渡到Objective - C
许多程序员从其他语言转向Objective - C和Cocoa时会遇到困难,因为Objective - C的行为与其他流行语言不同。以下是从几种常见语言过渡到Objective - C的要点:
3.1 从C语言过渡
Objective - C是在C语言的基础上增加了一些面向对象的特性。Objective - C程序员可以使用C语言的标准库,如
malloc()
和
free()
处理动态内存,
fopen()
和
fgets()
处理文件。
当调用使用回调的ANSI C库时,由于回调只适用于具有库要求签名的C函数,而实现Objective - C方法的函数需要先有
self
和
selector
参数,所以不能直接将Objective - C方法作为回调。不过,大多数回调库允许提供用户数据或指针。我们可以使用Objective - C对象的地址作为上下文指针,在回调中把上下文指针转换为对象类型并发送消息。以下是一个示例:
// 创建TreeWalker对象
TreeWalker *walker = [[TreeWalker alloc] init];
// 创建XML解析器
XMLParser parser;
parser = XMLParserLoadFile ("/tmp/badgers.xml");
// 设置回调函数并使用TreeWalker对象作为上下文
XMLSetParserCallback (parser, elementCallback, walker);
// 回调函数
void elementCallback (XMLParser *parser, XMLElement *element, userData *context)
{
TreeWalker *walker = (TreeWalker *) context;
[walker handleNewElement: element inParser: parser];
}
3.2 从C++语言过渡
C++有很多Objective - C缺乏的特性,如多重继承、命名空间、运算符重载、模板、类变量、抽象类和标准模板库等。不过,Objective - C有一些特性和技术可以替代或模拟这些功能。
-
多重继承的替代
:可以使用类别和协议来实现类似多重继承的功能,或者实现抽象基类。例如,协议可以用于提供纯抽象基类。但如果使用多重继承是为了引入额外的实例变量,类别和协议就无法满足需求,此时可以使用组合将一个对象包含在另一个对象中,并使用存根方法将消息重定向到第二个对象,也可以通过重写
forwardInvocation:
方法来模拟多重继承,但这种方法速度较慢且设置复杂。
-
其他特性的替代
:对于抽象类,可以使用调用
abort
的存根方法;对于命名空间,可以使用名称前缀。
C++和Objective - C在方法调度机制上有很大差异。C++使用基于虚函数表(vtable)的机制来确定调用的代码,这种方式速度快且安全,但不够灵活。而Objective - C使用运行时函数在各种类结构中查找要调用的代码,速度较慢,但增加了灵活性和便利性。
在Objective - C中,对象只需要有方法实现就可以被调用,允许任意对象成为其他对象的数据源和/或委托。但这也使得Objective - C的类型安全性不如C++,可能会出现运行时错误。Objective - C携带了大量关于类的元数据,可以使用反射来检查对象是否响应特定消息。此外,在Objective - C中可以向
nil
对象发送消息,消息发送到
nil
对象时是无操作的,返回值取决于方法的返回类型。
Objective - C没有类变量,可以使用文件作用域的全局变量并提供访问器来模拟。例如:
// 类声明
@interface Blarg : NSObject
{
}
+ (int) classVar;
+ (void) setClassVar: (int) cv;
@end
// 类实现
#import "Blarg.h"
static int g_cvar;
@implementation Blarg
+ (int) classVar
{
return (g_cvar);
}
+ (void) setClassVar: (int) cv
{
g_cvar = cv;
}
@end
Cocoa对象层次结构有一个共同的祖先类
NSObject
,而C++对象层次结构往往是多个具有不同根的树。
4. Objective - C++:融合两者优势
Xcode附带的Clang编译器支持一种名为Objective - C++的混合语言。这种语言允许自由混合C++和Objective - C代码,但有一些小的限制。使用
.mm
文件扩展名可以让编译器将代码视为Objective - C++。
在开发中,常见的场景是将应用程序的核心逻辑放入可移植的C++库中(如果是跨平台应用),并使用平台的原生工具包编写用户界面。Objective - C++为这种开发方式提供了很大的便利,既可以获得C++的性能和类型安全性,又可以利用Objective - C的动态特性和Cocoa工具包。
需要注意的是,Objective - C和C++的对象层次结构不能混合,不能有继承自
NSView
的C++类,也不能有继承自
std::string
的Objective - C类。
综上所述,无论是NSPredicate的强大过滤功能,还是从其他语言过渡到Objective - C的要点,都展示了Objective - C在编程领域的独特魅力和灵活性。通过合理运用这些知识,开发者可以更好地进行iOS和OS X应用程序的开发。
深入探索NSPredicate与不同语言过渡到Objective - C的要点(续)
5. 技术点分析与总结
在前面的内容中,我们详细介绍了NSPredicate的使用、从不同语言过渡到Objective - C的要点以及Objective - C++的特性。下面我们对这些技术点进行更深入的分析和总结。
5.1 NSPredicate技术分析
NSPredicate是Objective - C中用于过滤对象的强大工具,其核心在于通过谓词格式字符串来定义过滤规则。
-
字符串匹配运算符
:BEGINSWITH、ENDSWITH、CONTAINS等运算符提供了基本的字符串匹配功能,这些运算符区分大小写和重音符号,但可以通过
[c]、[d]或[cd]修饰符来忽略这些因素。例如,在实际开发中,如果需要对用户输入的搜索关键字进行匹配,就可以使用这些运算符,并且根据需求选择是否忽略大小写和重音符号,以提供更灵活的搜索体验。 -
LIKE运算符
:LIKE运算符使用问号
?和星号*进行模糊匹配,类似于SQL和Unix shell中的“globbing”。这种匹配方式在处理一些复杂的字符串匹配需求时非常有用,比如在搜索文件名、联系人姓名等场景中。 - MATCHES运算符 :MATCHES运算符支持正则表达式,正则表达式是一种非常强大的字符串匹配工具,但计算成本较高。在使用时,建议先使用基本的字符串运算符和比较运算符进行初步过滤,再使用MATCHES进行精确匹配,以提高性能。例如,在搜索包含特定格式的字符串时,可以先使用BEGINSWITH或CONTAINS进行初步筛选,再使用MATCHES进行最终的精确匹配。
5.2 从其他语言过渡到Objective - C的技术分析
从C和C++过渡到Objective - C时,需要理解两种语言之间的差异,并掌握相应的替代技术。
-
从C过渡 :Objective - C是在C的基础上发展而来的,保留了C的大部分特性。在处理回调时,由于C回调函数和Objective - C方法的签名不同,需要使用上下文指针来传递Objective - C对象。具体操作步骤如下:
-
创建Objective - C对象,如
TreeWalker *walker = [[TreeWalker alloc] init];。 -
初始化C库相关的结构体或对象,如
XMLParser parser = XMLParserLoadFile ("/tmp/badgers.xml");。 -
设置回调函数并传递Objective - C对象作为上下文,如
XMLSetParserCallback (parser, elementCallback, walker);。 -
在回调函数中,将上下文指针转换为Objective - C对象类型,并发送消息,如
TreeWalker *walker = (TreeWalker *) context; [walker handleNewElement: element inParser: parser];。
-
创建Objective - C对象,如
-
从C++过渡 :C++有很多Objective - C缺乏的特性,但Objective - C可以通过一些技术进行替代。
-
多重继承的替代 :
-
使用类别和协议:当需要实现接口或抽象基类时,可以使用类别和协议。例如,定义一个协议
@protocol MyProtocol <NSObject> - (void)myMethod; @end,然后让类实现该协议@interface MyClass : NSObject <MyProtocol> @end。 -
使用组合和存根方法:如果需要引入额外的实例变量,可以使用组合将一个对象包含在另一个对象中,并使用存根方法将消息重定向到第二个对象。例如,在
MyClass中包含一个AnotherClass对象,并在MyClass中实现存根方法来调用AnotherClass的方法。 -
重写
forwardInvocation:方法:通过重写该方法,可以模拟多重继承,但这种方法速度较慢且设置复杂。具体实现步骤如下:-
在类中重写
forwardInvocation:方法,如- (void)forwardInvocation:(NSInvocation *)anInvocation。 -
在方法中检查
anInvocation的选择器,如果该选择器应该由另一个对象处理,则将anInvocation转发给该对象。
-
在类中重写
-
使用类别和协议:当需要实现接口或抽象基类时,可以使用类别和协议。例如,定义一个协议
-
其他特性的替代 :
-
抽象类:使用调用
abort的存根方法来模拟抽象类,确保该类不会被实例化。 - 命名空间:使用名称前缀来区分不同类的方法和变量,避免命名冲突。
-
抽象类:使用调用
-
5.3 Objective - C++技术分析
Objective - C++是一种混合语言,结合了C++的性能和类型安全性以及Objective - C的动态特性和Cocoa工具包。在使用Objective - C++时,需要注意以下几点:
-
文件扩展名
:使用
.mm
文件扩展名让编译器将代码视为Objective - C++。
-
对象层次结构
:Objective - C和C++的对象层次结构不能混合,不能有C++类继承自
NSView
,也不能有Objective - C类继承自
std::string
。
在实际开发中,Objective - C++适用于将应用程序的核心逻辑放入C++库中,同时使用Objective - C和Cocoa工具包编写用户界面的场景。例如,开发一个跨平台的游戏应用,可以将游戏的核心算法和逻辑用C++实现,而将游戏的界面和交互部分用Objective - C和Cocoa实现,通过Objective - C++将两者结合起来。
6. 总结与展望
通过对NSPredicate、从不同语言过渡到Objective - C以及Objective - C++的学习,我们可以看到Objective - C在iOS和OS X开发中具有独特的优势。NSPredicate提供了强大的对象过滤功能,使得数据处理更加高效和灵活;从其他语言过渡到Objective - C的技术让开发者能够更好地利用已有的知识和经验;而Objective - C++则为开发者提供了一种融合C++和Objective - C优势的方式。
在未来的开发中,随着移动应用和操作系统的不断发展,Objective - C仍然会在iOS和OS X开发中发挥重要作用。同时,开发者也可以结合其他技术,如Swift语言、机器学习和人工智能等,进一步提升应用的性能和用户体验。
下面是一个简单的mermaid流程图,展示了从C++过渡到Objective - C时处理多重继承需求的选择流程:
graph TD;
A[需要多重继承功能?] -->|是| B[是否为引入额外实例变量?];
B -->|是| C[使用组合和存根方法或重写forwardInvocation:];
B -->|否| D[使用类别和协议];
A -->|否| E[使用其他替代技术];
总之,掌握这些技术要点,将有助于开发者更好地进行Objective - C编程,开发出高质量的iOS和OS X应用程序。希望本文能够为广大开发者提供有价值的参考和帮助。
超级会员免费看

被折叠的 条评论
为什么被折叠?



