草庐IT

ios - 属性、线程、内存管理和摇滚乐

coder 2024-01-16 原文

环境:Mac OS X 10.9、Xcode 5.0.2、ARC 禁用。

问题:所有线程完成作业后如何释放属性内存。请参见下面的示例。

我正在用一个按钮“(IBAction)btnRun:(id)sender”创建迷你示例。 示例读取 txt 文件并填充 NSArray 属性 (sharedListWords)。然后运行两个线程,每个线程显示单词,
请参阅OUT 部分。当线程完成一项工作时,属性 (self.sharedListWords) 不会被释放!但我想要为 (self.sharedListWords) 属性分配的空闲内存。 “btnRun”操作在线程完成作业之前退出,我无法在此操作中释放 (self.sharedListWords)。

如何在线程完成作业后释放属性 (self.sharedListWords) 的内存? 好的答案 here通过创建依赖操作jobFinished(),但是如何正确释放属性?

这是我在 Objective-c 上的第一个多线程程序,我很乐意进行调整。


AppDelegate.h:

#import <Cocoa/Cocoa.h>

@interface AppDelegate : NSObject <NSApplicationDelegate>
{
    volatile int32_t sharedIndex;   // Shared between threads, current index in array
    NSOperationQueue* operationQueue;
}
@property (assign) IBOutlet NSWindow *window;
// Shared between threads, list of words
@property (atomic, retain) NSArray* sharedListWords;
- (void)worker;

@end

AppDelegate.m:

#import "AppDelegate.h"

@implementation AppDelegate

- (IBAction)btnRun:(id)sender
{
    // Read txt file dictionary of words, where is each words in new line.
    NSString* dictionaryFilePath = [NSString stringWithFormat:@"/Users/admin/dictionary.txt"];
    NSString* fileContents = [NSString stringWithContentsOfFile:dictionaryFilePath
                                                       encoding:NSUTF8StringEncoding error:nil];
    // Get array of string separated by new line
    self.sharedListWords = [fileContents componentsSeparatedByCharactersInSet:
                                [NSCharacterSet newlineCharacterSet]];

    //self.sharedListWords = @[@"one",@"two",@"three",@"four",@"five",@"six",@"seven",@"eight",@"nine",@"ten"];

    self->sharedIndex = -1;

    int numberOfThreads = 2;

    // Run method working() in separate threads
    for(int i=0; i<numberOfThreads; ++i)
    {
        //////////////////////////////////////////
        // Create a thread
        // Create new NSOperatin object with function puting in @selector() for run in other thread.
        NSOperation* startBruteOper = [[NSInvocationOperation alloc]
                                       initWithTarget:self selector:@selector(worker) object:nil];
        // Add the operation to the queue and let it to be executed.
        [operationQueue addOperation:startBruteOper];
        [startBruteOper release];
        /////////////////////////////////////////
    }
}

- (void)worker
{
    unsigned long countWords = [self.sharedListWords count];

    int32_t index = 0;

    // Use atomic operation for thread safe
    while( (index = OSAtomicIncrement32( &(self->sharedIndex) ) ) < countWords )
    {
        NSLog(@"[%@] working on \"%@\"",
              [NSThread currentThread],
              [self.sharedListWords objectAtIndex:index]);
    }

    NSLog(@"[%@] work is finish.", [NSThread currentThread]);
}

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    // Multithreading queue list
    operationQueue = [[NSOperationQueue alloc] init];
}

@end

OUT 部分:

[<NSThread: num = 2}] working on "one"
[<NSThread: num = 3}] working on "two"
[<NSThread: num = 2}] working on "three"
[<NSThread: num = 3}] working on "four"
[<NSThread: num = 2}] working on "five"
[<NSThread: num = 3}] working on "six"
[<NSThread: num = 2}] working on "seven"
[<NSThread: num = 3}] working on "eight"
[<NSThread: num = 2}] working on "nine"
[<NSThread: num = 3}] working on "ten"
[<NSThread: num = 2}] work is finish.
[<NSThread: num = 3}] work is finish.

最佳答案

根据 Martins 的指示,这是正确的代码。

AppDelegate.h:

    #import <Cocoa/Cocoa.h>

    @interface AppDelegate : NSObject <NSApplicationDelegate>
    {
        volatile int32_t sharedIndex;   // Shared between threads, current index in array
        NSOperationQueue* operationQueue;
    }
    @property (assign) IBOutlet NSWindow *window;
    // Shared between threads, list of words
    @property (atomic, retain) NSArray* sharedListWords;
    - (void)worker;

    @end

AppDelegate.m:

    #import "AppDelegate.h"

    @implementation AppDelegate

    - (IBAction)btnRun:(id)sender
    {
        // Read txt file dictionary of words, where is each words in new line.
        NSString* dictionaryFilePath = [NSString stringWithFormat:@"/Users/admin/dictionary.txt"];
        NSString* fileContents = [NSString stringWithContentsOfFile:dictionaryFilePath
                                                           encoding:NSUTF8StringEncoding error:nil];
        // Get array of string separated by new line
        self.sharedListWords = [fileContents componentsSeparatedByCharactersInSet:
                                    [NSCharacterSet newlineCharacterSet]];

        //self.sharedListWords = @[@"one",@"two",@"three",@"four",@"five",@"six",@"seven",@"eight",@"nine",@"ten"];

        self->sharedIndex = -1;

        int numberOfThreads = 2;

        NSOperation* jobFinishedOper = [[NSInvocationOperation alloc]
                                    initWithTarget:self selector:@selector(jobFinished) object:nil];

        // Run method working() in separate threads
        for(int i=0; i<numberOfThreads; ++i)
        {
            //////////////////////////////////////////
            // Create a thread
            // Create new NSOperatin object with function puting in @selector() for run in other thread.
            NSOperation* startBruteOper = [[NSInvocationOperation alloc]
                                           initWithTarget:self selector:@selector(worker) object:nil];
            // Add the operation to the queue and let it to be executed.
            [operationQueue addOperation:startBruteOper];
            [jobFinishedOper addDependency:startBruteOper]; // 'jobFinishedOper' run only when 'startBruteOper' finished!
            [startBruteOper release];
            /////////////////////////////////////////
        }
        // 'jobFinishedOper' run only when all prevous operation is finished!
        [operationQueue addOperation:jobFinishedOper];
        [jobFinishedOper release];
    }

    - (void)worker
    {
        unsigned long countWords = [self.sharedListWords count];

        int32_t index = 0;

        // Use atomic operation for thread safe
        while( (index = OSAtomicIncrement32( &(self->sharedIndex) ) ) < countWords )
        {
            NSLog(@"[%@] working on \"%@\"",
                  [NSThread currentThread],
                  [self.sharedListWords objectAtIndex:index]);
        }

        NSLog(@"[%@] work is finish.", [NSThread currentThread]);
    }

    - (void)jobFinished
    {
        self.sharedListWords = nil;
    }

    - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
    {
        // Multithreading queue list
        operationQueue = [[NSOperationQueue alloc] init];
    }

    @end

关于ios - 属性、线程、内存管理和摇滚乐,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23412613/

有关ios - 属性、线程、内存管理和摇滚乐的更多相关文章

  1. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  2. ruby - i18n Assets 管理/翻译 UI - 2

    我正在使用i18n从头开始​​构建一个多语言网络应用程序,虽然我自己可以处理一大堆yml文件,但我说的语言(非常)有限,最终我想寻求外部帮助帮助。我想知道这里是否有人在使用UI插件/gem(与django上的django-rosetta不同)来处理多个翻译器,其中一些翻译器不愿意或无法处理存储库中的100多个文件,处理语言数据。谢谢&问候,安德拉斯(如果您已经在ruby​​onrails-talk上遇到了这个问题,我们深表歉意) 最佳答案 有一个rails3branchofthetolkgem在github上。您可以通过在Gemfi

  3. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

    我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

  4. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  5. ruby - 多个属性的 update_column 方法 - 2

    我有一个具有一些属性的模型:attr1、attr2和attr3。我需要在不执行回调和验证的情况下更新此属性。我找到了update_column方法,但我想同时更新三个属性。我需要这样的东西:update_columns({attr1:val1,attr2:val2,attr3:val3})代替update_column(attr1,val1)update_column(attr2,val2)update_column(attr3,val3) 最佳答案 您可以使用update_columns(attr1:val1,attr2:val2

  6. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  7. ruby - Nokogiri 剥离所有属性 - 2

    我有这个html标记:我想得到这个:我如何使用Nokogiri做到这一点? 最佳答案 require'nokogiri'doc=Nokogiri::HTML('')您可以通过xpath删除所有属性:doc.xpath('//@*').remove或者,如果您需要做一些更复杂的事情,有时使用以下方法遍历所有元素会更容易:doc.traversedo|node|node.keys.eachdo|attribute|node.deleteattributeendend 关于ruby-Nokog

  8. ruby-on-rails - Rails 模型——非持久类成员或属性? - 2

    对于Rails模型,是否可以/建议让一个类的成员不持久保存到数据库中?我想将用户最后选择的类型存储在session变量中。由于我无法从我的模型中设置session变量,我想将值存储在一个“虚拟”类成员中,该成员只是将值传递回Controller。你能有这样的类(class)成员吗? 最佳答案 将非持久属性添加到Rails模型就像任何其他Ruby类一样:classUser扩展解释:在Ruby中,所有实例变量都是私有(private)的,不需要在赋值前定义。attr_accessor创建一个setter和getter方法:classUs

  9. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  10. ruby-on-rails - Ruby 中的内存模型 - 2

    ruby如何管理内存。例如:如果我们在执行过程中采用C程序,则以下是内存模型。类似于这个ruby如何处理内存。C:__________________|||stack|||------------------||||------------------|||||Heap|||||__________________|||data|__________________|text|__________________Ruby:? 最佳答案 Ruby中没有“内存”这样的东西。Class#allocate分配一个对象并返回该对象。这就是程序

随机推荐