NSTask subclass 错误 - launchPath 仅为抽象 class 定义
NSTask subclass error - launchPath only defined for abstract class
我正在尝试创建 NSTask
的子类,为了显示状态,它增加了 name
和 activityDescription
属性, UI 在 OSX 桌面应用程序中。
但是,当我尝试在我的子类实例上设置 launchPath
或 arguments
属性 时,出现以下错误:
launchPath only defined for abstract class. Define -[Task launchPath]!
arguments only defined for abstract class. Define -[Task arguments]!
所以,我定义了 setLaunchPath:
和 setArguments:
如下所示,我仍然得到同样的错误。
对了,NSData stringValue定义在NSData+Additions.h:
- (NSString *) stringValue {
return [[NSString alloc] initWithData:self encoding:NSUTF8StringEncoding];
}
非常感谢任何帮助!
Task.h
#import <Foundation/Foundation.h>
@protocol TaskDelegate;
@interface Task : NSTask {
NSString *_launchTask;
NSArray *_arguments;
}
@property (weak, nonatomic) id<TaskDelegate> delegate;
@property (strong, nonatomic) NSString *name;
@property (strong, nonatomic) NSString *activityDescription;
//To be implemented by subclasses, should be called just before launch
- (void) setupTask;
- (BOOL) isConfigured;
//Launches the task - includes any setup required before the task is launched
- (void) launchAndWait;
- (void) setLaunchPath:(NSString *)launchPath;
- (void) setArguments:(NSArray *)arguments;
@end
@protocol TaskDelegate <NSObject>
- (void) task:(Task *)task didReceiveTaskError:(NSString *)errorString;
@end
Task.m
#import "Task.h"
#import "NSData+Additions.h"
@interface Task ()
@end
@implementation Task
- (id) init
{
self = [super init];
if (self) {
}
return self;
}
- (void) errorOccurred:(NSNotification *)notification {
if (_delegate) {
NSData *readData = [[notification userInfo] objectForKey:NSFileHandleNotificationDataItem];
NSString *outputString = [readData stringValue];
if (outputString.length)
[_delegate task:self didReceiveTaskError:outputString];
}
}
- (void) setupTask
{
//To be implemented by subclasses
}
- (BOOL) isConfigured
{
return (self.launchPath != nil);
}
//Process task conguration and execution is optional - if process task is not configured, this returns immediately
- (void) launchAndWait
{
//Allow setupTask to be used, without actually launching
if (![self isConfigured])
return;
NSPipe *errorPipe = [NSPipe pipe];
self.standardError = errorPipe;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(errorOccurred:)
name:NSFileHandleReadToEndOfFileCompletionNotification
object:[errorPipe fileHandleForReading]];
[[errorPipe fileHandleForReading] readToEndOfFileInBackgroundAndNotify];
[self launch];
[self waitUntilExit];
//Tear down
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void) setLaunchPath:(NSString *)launchPath
{
_launchTask = launchPath;
}
- (void) setArguments:(NSArray *)arguments
{
_arguments = arguments;
}
@end
我决定使用组合方法并在我的 Task
class 中使用 NSTask
,而不是继承,并且它运行良好。
这是更新后的 class:
Task.h
#import <Foundation/Foundation.h>
@protocol TaskDelegate;
@interface Task : NSObject {
__weak id<TaskDelegate> _delegate;
NSTask *_processTask;
}
@property (weak, nonatomic) id<TaskDelegate> delegate;
@property (strong, nonatomic) NSString *name;
@property (strong, nonatomic) NSString *activityDescription;
//To be called just before launch
- (void) setupTask;
- (BOOL) processTaskConfigured;
//Launches the task - includes any setup required before the task is launched
- (void) launchAndWait;
//////////////////////////////////////////////////////////////////////////////////////////////// Process task delegation
@property (readonly) int terminationStatus;
- (BOOL) isRunning;
- (void) terminate;
@end
@protocol TaskDelegate <NSObject>
- (void) task:(Task *)task didReceiveTaskError:(NSString *)errorString;
@end
Task.m
#import "Task.h"
#import "NSData+Additions.h"
@interface Task ()
//Delegating to NSTask
@property (strong, nonatomic) NSTask *processTask;
@end
@implementation Task
- (id) init
{
self = [super init];
if (self) {
self.processTask = [NSTask new];
}
return self;
}
- (void) errorOccurred:(NSNotification *)notification {
if (_delegate) {
NSData *readData = [[notification userInfo] objectForKey:NSFileHandleNotificationDataItem];
NSString *outputString = [readData stringValue];
if (outputString.length)
[_delegate task:self didReceiveTaskError:outputString];
}
}
- (void) setupTask
{
//To be implemented by subclasses
}
- (BOOL) processTaskConfigured
{
return (_processTask.launchPath != nil);
}
//Process task conguration and execution is optional - if process task is not configured, this returns immediately
- (void) launchAndWait
{
if (!_processTask.launchPath)
return;
NSPipe *errorPipe = [NSPipe pipe];
_processTask.standardError = errorPipe;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(errorOccurred:)
name:NSFileHandleReadToEndOfFileCompletionNotification
object:[errorPipe fileHandleForReading]];
[[errorPipe fileHandleForReading] readToEndOfFileInBackgroundAndNotify];
[_processTask launch];
[_processTask waitUntilExit];
//Tear down
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
////////////////////////////////////////////////////////////////////////////////////////// Process task delegation
- (int) terminationStatus
{
if ([self processTaskConfigured]) {
return [_processTask terminationStatus];
}
return 0;
}
- (BOOL) isRunning
{
return [_processTask isRunning];
}
- (void) terminate
{
if ([self processTaskConfigured]) {
[_processTask terminate];
}
}
@end
我正在尝试创建 NSTask
的子类,为了显示状态,它增加了 name
和 activityDescription
属性, UI 在 OSX 桌面应用程序中。
但是,当我尝试在我的子类实例上设置 launchPath
或 arguments
属性 时,出现以下错误:
launchPath only defined for abstract class. Define -[Task launchPath]!
arguments only defined for abstract class. Define -[Task arguments]!
所以,我定义了 setLaunchPath:
和 setArguments:
如下所示,我仍然得到同样的错误。
对了,NSData stringValue定义在NSData+Additions.h:
- (NSString *) stringValue {
return [[NSString alloc] initWithData:self encoding:NSUTF8StringEncoding];
}
非常感谢任何帮助!
Task.h
#import <Foundation/Foundation.h>
@protocol TaskDelegate;
@interface Task : NSTask {
NSString *_launchTask;
NSArray *_arguments;
}
@property (weak, nonatomic) id<TaskDelegate> delegate;
@property (strong, nonatomic) NSString *name;
@property (strong, nonatomic) NSString *activityDescription;
//To be implemented by subclasses, should be called just before launch
- (void) setupTask;
- (BOOL) isConfigured;
//Launches the task - includes any setup required before the task is launched
- (void) launchAndWait;
- (void) setLaunchPath:(NSString *)launchPath;
- (void) setArguments:(NSArray *)arguments;
@end
@protocol TaskDelegate <NSObject>
- (void) task:(Task *)task didReceiveTaskError:(NSString *)errorString;
@end
Task.m
#import "Task.h"
#import "NSData+Additions.h"
@interface Task ()
@end
@implementation Task
- (id) init
{
self = [super init];
if (self) {
}
return self;
}
- (void) errorOccurred:(NSNotification *)notification {
if (_delegate) {
NSData *readData = [[notification userInfo] objectForKey:NSFileHandleNotificationDataItem];
NSString *outputString = [readData stringValue];
if (outputString.length)
[_delegate task:self didReceiveTaskError:outputString];
}
}
- (void) setupTask
{
//To be implemented by subclasses
}
- (BOOL) isConfigured
{
return (self.launchPath != nil);
}
//Process task conguration and execution is optional - if process task is not configured, this returns immediately
- (void) launchAndWait
{
//Allow setupTask to be used, without actually launching
if (![self isConfigured])
return;
NSPipe *errorPipe = [NSPipe pipe];
self.standardError = errorPipe;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(errorOccurred:)
name:NSFileHandleReadToEndOfFileCompletionNotification
object:[errorPipe fileHandleForReading]];
[[errorPipe fileHandleForReading] readToEndOfFileInBackgroundAndNotify];
[self launch];
[self waitUntilExit];
//Tear down
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void) setLaunchPath:(NSString *)launchPath
{
_launchTask = launchPath;
}
- (void) setArguments:(NSArray *)arguments
{
_arguments = arguments;
}
@end
我决定使用组合方法并在我的 Task
class 中使用 NSTask
,而不是继承,并且它运行良好。
这是更新后的 class:
Task.h
#import <Foundation/Foundation.h>
@protocol TaskDelegate;
@interface Task : NSObject {
__weak id<TaskDelegate> _delegate;
NSTask *_processTask;
}
@property (weak, nonatomic) id<TaskDelegate> delegate;
@property (strong, nonatomic) NSString *name;
@property (strong, nonatomic) NSString *activityDescription;
//To be called just before launch
- (void) setupTask;
- (BOOL) processTaskConfigured;
//Launches the task - includes any setup required before the task is launched
- (void) launchAndWait;
//////////////////////////////////////////////////////////////////////////////////////////////// Process task delegation
@property (readonly) int terminationStatus;
- (BOOL) isRunning;
- (void) terminate;
@end
@protocol TaskDelegate <NSObject>
- (void) task:(Task *)task didReceiveTaskError:(NSString *)errorString;
@end
Task.m
#import "Task.h"
#import "NSData+Additions.h"
@interface Task ()
//Delegating to NSTask
@property (strong, nonatomic) NSTask *processTask;
@end
@implementation Task
- (id) init
{
self = [super init];
if (self) {
self.processTask = [NSTask new];
}
return self;
}
- (void) errorOccurred:(NSNotification *)notification {
if (_delegate) {
NSData *readData = [[notification userInfo] objectForKey:NSFileHandleNotificationDataItem];
NSString *outputString = [readData stringValue];
if (outputString.length)
[_delegate task:self didReceiveTaskError:outputString];
}
}
- (void) setupTask
{
//To be implemented by subclasses
}
- (BOOL) processTaskConfigured
{
return (_processTask.launchPath != nil);
}
//Process task conguration and execution is optional - if process task is not configured, this returns immediately
- (void) launchAndWait
{
if (!_processTask.launchPath)
return;
NSPipe *errorPipe = [NSPipe pipe];
_processTask.standardError = errorPipe;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(errorOccurred:)
name:NSFileHandleReadToEndOfFileCompletionNotification
object:[errorPipe fileHandleForReading]];
[[errorPipe fileHandleForReading] readToEndOfFileInBackgroundAndNotify];
[_processTask launch];
[_processTask waitUntilExit];
//Tear down
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
////////////////////////////////////////////////////////////////////////////////////////// Process task delegation
- (int) terminationStatus
{
if ([self processTaskConfigured]) {
return [_processTask terminationStatus];
}
return 0;
}
- (BOOL) isRunning
{
return [_processTask isRunning];
}
- (void) terminate
{
if ([self processTaskConfigured]) {
[_processTask terminate];
}
}
@end