草庐IT

objective-c - 如何迭代 NSArray?

coder 2023-04-25 原文

我正在寻找迭代 NSArray 的标准习语。我的代码需要适用于 OS X 10.4+。

最佳答案

10.5+/iOS 的普遍首选代码。

for (id object in array) {
    // do something with object
}

此构造用于枚举符合 NSFastEnumeration 的集合中的对象。协议(protocol)。这种方法具有速度优势,因为它将指向多个对象(通过单个方法调用获得)的指针存储在缓冲区中,并通过使用指针算法在缓冲区中前进来迭代它们。这比每次循环调用 -objectAtIndex:很多

还值得注意的是,虽然您在技术上可以使用 for-in 循环来单步执行 NSEnumerator,但我发现这几乎抵消了所有速度优势的快速枚举。原因是 -countByEnumeratingWithState:objects:count: 的默认 NSEnumerator 实现在每次调用时只在缓冲区中放置一个对象。

我在 radar://6296108 中报告了这一点(NSEnumerators 的快速枚举速度很慢),但它被返回为 Not To Be Fixed。原因是快速枚举会预取一组对象,如果您只想枚举到枚举器中的给定点(例如,直到找到特定对象或满足条件)并在中断后使用相同的枚举器在循环中,通常会跳过几个对象。

如果您正在为 OS X 10.6/iOS 4.0 及更高版本进行编码,您还可以选择使用基于 block 的 API 来枚举数组和其他集合:

[array enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
    // do something with object
}];

您也可以使用 -enumerateObjectsWithOptions:usingBlock: 并传递 NSEnumerationConcurrent 和/或 NSEnumerationReverse 作为选项参数。


10.4 或更早版本

10.5 之前的标准习惯用法是使用 NSEnumerator 和 while 循环,如下所示:

NSEnumerator *e = [array objectEnumerator];
id object;
while (object = [e nextObject]) {
  // do something with object
}

我建议保持简单。将自己绑定(bind)到数组类型是不灵活的,并且声称使用 -objectAtIndex: 的速度提高对于 10.5+ 上的快速枚举的改进是微不足道的。 (快速枚举实际上在底层数据结构上使用了指针算法,并消除了大部分方法调用开销。)过早的优化从来都不是一个好主意——它会导致更困惑的代码来解决一个无论如何都不是你的瓶颈的问题。

当使用 -objectEnumerator 时,您可以很容易地更改为另一个可枚举集合(如 NSSet,键入 NSDictionary 等),甚至切换到 -reverseObjectEnumerator 以向后枚举数组,所有这些都无需更改其他代码。如果迭代代码在一个方法中,您甚至可以传入任何 NSEnumerator 并且代码甚至不必关心它正在迭代的 什么。此外,只要有更多对象,NSEnumerator(至少由 Apple 代码提供的那些)就会保留它正在枚举的集合,因此您不必担心自动释放的对象将存在多长时间。

NSEnumerator(或快速枚举)保护您免受的最大影响可能是在您在您不知情的情况下重新列举它。如果您按索引访问对象,您可能会遇到奇怪的异常或一个错误(通常在问题发生很久之后),这对于调试来说可能是可怕的。使用标准惯用语之一进行枚举具有“快速失败”行为,因此当您在发生突变后尝试访问下一个对象时,问题(由不正确的代码引起)将立即显现出来。随着程序变得越来越复杂和多线程,甚至依赖于第三方代码可能修改的东西,脆弱的枚举代码变得越来越成问题。封装和抽象 FTW! :-)


关于objective-c - 如何迭代 NSArray?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/992901/

有关objective-c - 如何迭代 NSArray?的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  4. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  5. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  6. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  7. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  8. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  9. ruby - 如何每月在 Heroku 运行一次 Scheduler 插件? - 2

    在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/

  10. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

随机推荐