33、深入探索NSPredicate与不同语言过渡到Objective - C的要点

深入探索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对象。具体操作步骤如下:

    1. 创建Objective - C对象,如 TreeWalker *walker = [[TreeWalker alloc] init];
    2. 初始化C库相关的结构体或对象,如 XMLParser parser = XMLParserLoadFile ("/tmp/badgers.xml");
    3. 设置回调函数并传递Objective - C对象作为上下文,如 XMLSetParserCallback (parser, elementCallback, walker);
    4. 在回调函数中,将上下文指针转换为Objective - C对象类型,并发送消息,如 TreeWalker *walker = (TreeWalker *) context; [walker handleNewElement: element inParser: parser];
  • 从C++过渡 :C++有很多Objective - C缺乏的特性,但Objective - C可以通过一些技术进行替代。

    • 多重继承的替代

      • 使用类别和协议:当需要实现接口或抽象基类时,可以使用类别和协议。例如,定义一个协议 @protocol MyProtocol <NSObject> - (void)myMethod; @end ,然后让类实现该协议 @interface MyClass : NSObject <MyProtocol> @end
      • 使用组合和存根方法:如果需要引入额外的实例变量,可以使用组合将一个对象包含在另一个对象中,并使用存根方法将消息重定向到第二个对象。例如,在 MyClass 中包含一个 AnotherClass 对象,并在 MyClass 中实现存根方法来调用 AnotherClass 的方法。
      • 重写 forwardInvocation: 方法:通过重写该方法,可以模拟多重继承,但这种方法速度较慢且设置复杂。具体实现步骤如下:
        1. 在类中重写 forwardInvocation: 方法,如 - (void)forwardInvocation:(NSInvocation *)anInvocation
        2. 在方法中检查 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应用程序。希望本文能够为广大开发者提供有价值的参考和帮助。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值