SHOW:
|
|
- or go back to the newest paste.
1 | - | //SCTaskRunner.h |
1 | + | //// header |
2 | #import <Foundation/Foundation.h> | |
3 | @class SCTaskRunner; | |
4 | @protocol SCTaskRunnerDelegate <NSObject> | |
5 | @optional | |
6 | - (void) taskRunner:(SCTaskRunner *) taskRunner didReadData:(NSData *) data; | |
7 | - (void) taskRunner:(SCTaskRunner *) taskRunner didReadDataFromStdOut:(NSData *) data; | |
8 | - (void) taskRunner:(SCTaskRunner *) taskRunner didReadDataFromStdErr:(NSData *) data; | |
9 | - (void) taskRunnerTerminated:(SCTaskRunner *) taskRunner; | |
10 | - | @interface SCTaskRunner : NSObject |
10 | + | |
11 | ||
12 | @interface SCTaskRunner : NSObject { | |
13 | BOOL _terminated; | |
14 | } | |
15 | @property (assign) NSObject <SCTaskRunnerDelegate> * delegate; | |
16 | @property BOOL collectDataUntilTerminated; | |
17 | @property NSTask * task; | |
18 | @property NSPipe * standardInput; | |
19 | - | //SCTaskRunner.m |
19 | + | |
20 | @property NSPipe * standardError; | |
21 | @property NSMutableData * data; | |
22 | - (id) initWithStandardInput:(NSPipe *) pipe; | |
23 | @end | |
24 | ||
25 | ////implementation | |
26 | ||
27 | #import "SCTaskRunner.h" | |
28 | ||
29 | @implementation SCTaskRunner | |
30 | ||
31 | - (id) init { | |
32 | self = [super init]; | |
33 | self.task = [[NSTask alloc] init]; | |
34 | self.data = [NSMutableData data]; | |
35 | [self setupPipesAndNotifications]; | |
36 | return self; | |
37 | } | |
38 | ||
39 | - (id) initWithStandardInput:(NSPipe *) standardInput { | |
40 | self = [self init]; | |
41 | self.standardInput = standardInput; | |
42 | return self; | |
43 | } | |
44 | ||
45 | - (void) setupPipesAndNotifications { | |
46 | self.standardOutput = [[NSPipe alloc] init]; | |
47 | self.standardError = [[NSPipe alloc] init]; | |
48 | self.task.standardOutput = self.standardOutput; | |
49 | - | [nfc addObserver:self selector:@selector(dataAvailable:) name:NSFileHandleReadCompletionNotification object:self.standardOutput.fileHandleForReading]; |
49 | + | |
50 | - | [nfc addObserver:self selector:@selector(dataAvailable:) name:NSFileHandleReadCompletionNotification object:self.standardError.fileHandleForReading]; |
50 | + | |
51 | - | [self.standardOutput.fileHandleForReading readInBackgroundAndNotify]; |
51 | + | |
52 | - | [self.standardError.fileHandleForReading readInBackgroundAndNotify]; |
52 | + | |
53 | //add notification to task for termination | |
54 | [nfc addObserver:self selector:@selector(taskTerminated:) name:NSTaskDidTerminateNotification object:self.task]; | |
55 | ||
56 | //add notifications for read data on standard out and standard error | |
57 | [nfc addObserver:self selector:@selector(dataAvailable:) name:NSFileHandleDataAvailableNotification object:self.standardOutput.fileHandleForReading]; | |
58 | [nfc addObserver:self selector:@selector(dataAvailable:) name:NSFileHandleDataAvailableNotification object:self.standardError.fileHandleForReading]; | |
59 | [self.standardOutput.fileHandleForReading waitForDataInBackgroundAndNotify]; | |
60 | - | NSData * data = [notification.userInfo objectForKey:NSFileHandleNotificationDataItem]; |
60 | + | [self.standardError.fileHandleForReading waitForDataInBackgroundAndNotify]; |
61 | - | if(notification.object == self.standardOutput.fileHandleForReading) { |
61 | + | |
62 | - | if(self.delegate && [self.delegate respondsToSelector:@selector(taskRunner:didReadDataFromStdOut:)]) { |
62 | + | |
63 | - | [self.delegate taskRunner:self didReadDataFromStdOut:data]; |
63 | + | |
64 | } | |
65 | - | } else if(notification.object == self.standardError.fileHandleForReading) { |
65 | + | |
66 | - | if(self.delegate && [self.delegate respondsToSelector:@selector(taskRunner:didReadDataFromStdErr:)]) { |
66 | + | |
67 | - | [self.delegate taskRunner:self didReadDataFromStdErr:data]; |
67 | + | - (void) dataAvailableForFileHandle:(NSFileHandle *) fileHandle { |
68 | NSData * data = [fileHandle availableData]; | |
69 | ||
70 | if(data.length > 0) { | |
71 | if(self.collectDataUntilTerminated) { | |
72 | [self.data appendData:data]; | |
73 | } else { | |
74 | ||
75 | if(self.delegate && [self.delegate respondsToSelector:@selector(taskRunner:didReadData:)]) { | |
76 | [self.delegate taskRunner:self didReadData:data]; | |
77 | } | |
78 | ||
79 | if(fileHandle == self.standardOutput.fileHandleForReading) { | |
80 | if(self.delegate && [self.delegate respondsToSelector:@selector(taskRunner:didReadDataFromStdOut:)]) { | |
81 | [self.delegate taskRunner:self didReadDataFromStdOut:data]; | |
82 | } | |
83 | } | |
84 | ||
85 | if(fileHandle == self.standardError.fileHandleForReading) { | |
86 | if(self.delegate && [self.delegate respondsToSelector:@selector(taskRunner:didReadDataFromStdErr:)]) { | |
87 | [self.delegate taskRunner:self didReadDataFromStdErr:data]; | |
88 | } | |
89 | } | |
90 | } | |
91 | } | |
92 | ||
93 | if(!_terminated) { | |
94 | [fileHandle waitForDataInBackgroundAndNotify]; | |
95 | } | |
96 | } | |
97 | ||
98 | - (void) dataAvailable:(NSNotification *) notification { | |
99 | NSFileHandle * fileHandle = notification.object; | |
100 | [self dataAvailableForFileHandle:fileHandle]; | |
101 | } | |
102 | ||
103 | - (void) taskTerminated:(NSNotification *) notification { | |
104 | _terminated = TRUE; | |
105 | [self dataAvailableForFileHandle:self.standardOutput.fileHandleForReading]; | |
106 | [self dataAvailableForFileHandle:self.standardError.fileHandleForReading]; | |
107 | if(self.delegate && [self.delegate respondsToSelector:@selector(taskRunnerTerminated:)]) { | |
108 | [self.delegate taskRunnerTerminated:self]; | |
109 | } | |
110 | } | |
111 | ||
112 | - (void) dealloc { | |
113 | NSLog(@"DEALLOC: SCTaskRunner"); | |
114 | [[NSNotificationCenter defaultCenter] removeObserver:self]; | |
115 | [self.task terminate]; | |
116 | self.task = nil; | |
117 | self.delegate = nil; | |
118 | self.standardOutput = nil; | |
119 | self.standardError = nil; | |
120 | self.standardInput = nil; | |
121 | } | |
122 | ||
123 | @end |