0

Q1:我可以调用一个方法并让它从另一个当前正在主线程上执行的方法内部在后台线程上执行吗?

Q2:作为上述的扩展,我可以调用一个方法并让它从另一个当前正在其他后台线程本身上执行的方法内部在后台线程上执行吗?

Q3:最后一个问题是:如果我在某个线程(主/后台)上初始化某个对象 X 的一个实例,然后在某个其他后台线程上执行该对象 X 的方法 Y,这个方法 Y 可以吗?发送消息并更新一个int property(例如那个对象 X,或者这样的通信是不可能的?

我问最后一个问题的原因是因为我一遍又一遍地重复它,我不知道这里出了什么问题:

以下代码返回零加速度和零度值:

运动处理器.m

@implementation MotionHandler

@synthesize currentAccelerationOnYaxis; // this is a double

-(void)startCompassUpdates
{
    locationManager=[[CLLocationManager alloc] init];
    locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    locationManager.delegate=self;
    [locationManager startUpdatingHeading];
    NSLog(@"compass updates initialized");
}

-(int) currentDegrees
{
    return (int)locationManager.heading.magneticHeading;
}
-(void) startAccelerationUpdates
{
    CMMotionManager *motionManager = [[CMMotionManager alloc] init];
    motionManager.deviceMotionUpdateInterval = 0.01;
    [motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue currentQueue]
                                       withHandler:^(CMDeviceMotion *motion, NSError *error)
                                       {
                                           self.currentAccelerationOnYaxis = motion.userAcceleration.y;
                                       }
    ];
}

@end

测试者.m

@implementation Tester

-(void)test
{
    MotionHandler *currentMotionHandler = [[MotionHandler alloc] init];

    [currentMotionHandler performSelectorInBackground:@selector(startCompassUpdates) withObject:nil];

    [currentMotionHandler performSelectorInBackground:@selector(startAccelerationUpdates) withObject:nil];

    while(1==1)
    {
        NSLog(@"current acceleration is %f", currentMotionHandler.currentAccelerationOnYaxis);
        NSLog(@"current degrees are %i", [currentMotionHandler currentDegrees]);
    }

SomeViewController.m

@implementation SomeViewController
-(void) viewDidLoad
{
    [myTester performSelectorInBackground:@selector(test) withObject:nil];
}
@end

但是,以下代码通常会返回这些值:

测试者.m

@interface Tester()
{
    CLLocationManager *locationManager;
    double accelerationOnYaxis;
    // more code..
}
@end

@implementation Tester

- (id) init
{
    locationManager=[[CLLocationManager alloc] init];
    locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    locationManager.delegate=self;
    [locationManager startUpdatingHeading];

    // more code..
}


-(void) test
{
    CMMotionManager *motionManager = [[CMMotionManager alloc] init];
    motionManager.deviceMotionUpdateInterval = 0.01;
    [motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue mainQueue]
                                       withHandler:^(CMDeviceMotion *motion, NSError *error)
     {
         accelerationOnYaxis = motion.userAcceleration.y;
     }
     ];

     while(1==1)
    {
        NSLog(@"current acceleration is %f", accelerationOnYaxis);
        NSLog(@"current degrees are %i", locationManager.heading.magneticHeading);
    }
}

SomeViewController.m

@implementation SomeViewController

-(void) viewDidLoad
{
    [myTester performSelectorInBackground:@selector(test) withObject:nil];
}

第一个版本有什么问题?我真的很想使用第一个,因为它在设计方面似乎要好得多。谢谢您的帮助!

4

2 回答 2

1

您应该查看来自 Apple 的 Grand Central Dispatch 文档。它允许您在基于块的结构中使用多个线程。

2 个重要功能是dispatch_sync()dispatch_async()

一些例子:

在后台线程上执行某个代码块并等待它完成:

__block id someVariable = nil;
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
    // do some heavy work in the background

    someVariable = [[NSObject alloc] init];
});

NSLog(@"Variable: %@", someVariable);

此函数修改变量 someVariable,您可以稍后使用。请注意,主线程将暂停以等待后台线程。如果这不是你想要的,你可以使用dispatch_async()如下:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
    // do some heavy work in the background

    NSObject *someVariable = [[NSObject alloc] init];

    // notify main thread that the work is done
    dispatch_async(dispatch_get_main_queue(), ^{
        // call some function and pass someVariable to it, it will be called on the main thread
        NSLog(@"Variable: %@", someVariable);
    });
});
于 2012-08-22T15:13:33.340 回答
1

调用与以当前对象、选择器和参数对象为参数performSelectorInBackground:withObject:调用的detachNewThreadSelector:toTarget:withObject:方法相同(线程编程指南)。无论您在哪里调用它,都会创建一个新线程来执行该选择器。所以回答你的前两个问题:是的,是的。NSThread

对于您的最后一个问题,只要此 Object X 在两种方法中都是同一个对象,就可以更新 X 的任何属性。但是,请注意这可能会产生意想不到的结果(即参见并发编程指南)。如果多个方法正在更新 X 的属性,则可以覆盖或忽略值。但是,如果您只是从方法 Y 更新它并从所有其他方法读取它,则不应出现此类问题。

于 2012-08-22T15:06:34.223 回答