SendController.m
上传用户:ccvv88
上传日期:2020-08-12
资源大小:97k
文件大小:10k
- /*
- File: SendController.m
- Contains: Manages the Send tab.
- Written by: DTS
- Copyright: Copyright (c) 2009 Apple Inc. All Rights Reserved.
- Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc.
- ("Apple") in consideration of your agreement to the following
- terms, and your use, installation, modification or
- redistribution of this Apple software constitutes acceptance of
- these terms. If you do not agree with these terms, please do
- not use, install, modify or redistribute this Apple software.
- In consideration of your agreement to abide by the following
- terms, and subject to these terms, Apple grants you a personal,
- non-exclusive license, under Apple's copyrights in this
- original Apple software (the "Apple Software"), to use,
- reproduce, modify and redistribute the Apple Software, with or
- without modifications, in source and/or binary forms; provided
- that if you redistribute the Apple Software in its entirety and
- without modifications, you must retain this notice and the
- following text and disclaimers in all such redistributions of
- the Apple Software. Neither the name, trademarks, service marks
- or logos of Apple Inc. may be used to endorse or promote
- products derived from the Apple Software without specific prior
- written permission from Apple. Except as expressly stated in
- this notice, no other rights or licenses, express or implied,
- are granted by Apple herein, including but not limited to any
- patent rights that may be infringed by your derivative works or
- by other works in which the Apple Software may be incorporated.
- The Apple Software is provided by Apple on an "AS IS" basis.
- APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
- WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT,
- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING
- THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
- COMBINATION WITH YOUR PRODUCTS.
- IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT,
- INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY
- OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
- OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY
- OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR
- OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGE.
- */
- #import "SendController.h"
- #import "AppDelegate.h"
- @interface SendController ()
- // Properties that don't need to be seen by the outside world.
- @property (nonatomic, readonly) BOOL isSending;
- @property (nonatomic, retain) NSNetService * netService;
- @property (nonatomic, retain) NSOutputStream * networkStream;
- @property (nonatomic, retain) NSInputStream * fileStream;
- @property (nonatomic, readonly) uint8_t * buffer;
- @property (nonatomic, assign) size_t bufferOffset;
- @property (nonatomic, assign) size_t bufferLimit;
- @end
- @implementation SendController
- #pragma mark * Status management
- // These methods are used by the core transfer code to update the UI.
- - (void)_sendDidStart
- {
- self.statusLabel.text = @"Sending";
- self.cancelButton.enabled = YES;
- [self.activityIndicator startAnimating];
- [[AppDelegate sharedAppDelegate] didStartNetworking];
- }
- - (void)_updateStatus:(NSString *)statusString
- {
- assert(statusString != nil);
- self.statusLabel.text = statusString;
- }
- - (void)_sendDidStopWithStatus:(NSString *)statusString
- {
- if (statusString == nil) {
- statusString = @"Send succeeded";
- }
- self.statusLabel.text = statusString;
- self.cancelButton.enabled = NO;
- [self.activityIndicator stopAnimating];
- [[AppDelegate sharedAppDelegate] didStopNetworking];
- }
- #pragma mark * Core transfer code
- // This is the code that actually does the networking.
- @synthesize netService = _netService;
- @synthesize networkStream = _networkStream;
- @synthesize fileStream = _fileStream;
- @synthesize bufferOffset = _bufferOffset;
- @synthesize bufferLimit = _bufferLimit;
- // Because buffer is declared as an array, you have to use a custom getter.
- // A synthesised getter doesn't compile.
- - (uint8_t *)buffer
- {
- return self->_buffer;
- }
- - (BOOL)isSending
- {
- return (self.networkStream != nil);
- }
- - (void)_startSend:(NSString *)filePath
- {
- NSOutputStream * output;
- BOOL success;
-
- assert(filePath != nil);
-
- assert(self.networkStream == nil); // don't tap send twice in a row!
- assert(self.fileStream == nil); // ditto
- // Open a stream for the file we're going to send.
-
- self.fileStream = [NSInputStream inputStreamWithFileAtPath:filePath];
- assert(self.fileStream != nil);
-
- [self.fileStream open];
-
- // Open a stream to the server, finding the server via Bonjour. Then configure
- // the stream for async operation.
-
- self.netService = [[[NSNetService alloc] initWithDomain:@"local." type:@"_x-SNSUpload._tcp." name:@"Test"] autorelease];
- assert(self.netService != nil);
- success = [self.netService getInputStream:NULL outputStream:&output];
- assert(success);
-
- self.networkStream = output;
-
- // -[NSNetService getInputStream:outputStream:] currently returns the stream
- // with a reference that we have to release (something that's counter to the
- // standard Cocoa memory management rules <rdar://problem/6868813>).
-
- [output release];
-
- self.networkStream.delegate = self;
- [self.networkStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
-
- [self.networkStream open];
-
- // Tell the UI we're sending.
-
- [self _sendDidStart];
- }
- - (void)_stopSendWithStatus:(NSString *)statusString
- {
- if (self.networkStream != nil) {
- self.networkStream.delegate = nil;
- [self.networkStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
- [self.networkStream close];
- self.networkStream = nil;
- }
- if (self.netService != nil) {
- [self.netService stop];
- self.netService = nil;
- }
- if (self.fileStream != nil) {
- [self.fileStream close];
- self.fileStream = nil;
- }
- self.bufferOffset = 0;
- self.bufferLimit = 0;
- [self _sendDidStopWithStatus:statusString];
- }
- - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
- // An NSStream delegate callback that's called when events happen on our
- // network stream.
- {
- #pragma unused(aStream)
- assert(aStream == self.networkStream);
- switch (eventCode) {
- case NSStreamEventOpenCompleted: {
- [self _updateStatus:@"Opened connection"];
- } break;
- case NSStreamEventHasBytesAvailable: {
- assert(NO); // should never happen for the output stream
- } break;
- case NSStreamEventHasSpaceAvailable: {
- [self _updateStatus:@"Sending"];
-
- // If we don't have any data buffered, go read the next chunk of data.
-
- if (self.bufferOffset == self.bufferLimit) {
- NSInteger bytesRead;
-
- bytesRead = [self.fileStream read:self.buffer maxLength:kSendBufferSize];
-
- if (bytesRead == -1) {
- [self _stopSendWithStatus:@"File read error"];
- } else if (bytesRead == 0) {
- [self _stopSendWithStatus:nil];
- } else {
- self.bufferOffset = 0;
- self.bufferLimit = bytesRead;
- }
- }
-
- // If we're not out of data completely, send the next chunk.
-
- if (self.bufferOffset != self.bufferLimit) {
- NSInteger bytesWritten;
- bytesWritten = [self.networkStream write:&self.buffer[self.bufferOffset] maxLength:self.bufferLimit - self.bufferOffset];
- assert(bytesWritten != 0);
- if (bytesWritten == -1) {
- [self _stopSendWithStatus:@"Network write error"];
- } else {
- self.bufferOffset += bytesWritten;
- }
- }
- } break;
- case NSStreamEventErrorOccurred: {
- [self _stopSendWithStatus:@"Stream open error"];
- } break;
- case NSStreamEventEndEncountered: {
- // ignore
- } break;
- default: {
- assert(NO);
- } break;
- }
- }
- #pragma mark * Actions
- - (IBAction)sendAction:(UIView *)sender
- {
- assert( [sender isKindOfClass:[UIView class]] );
- if ( ! self.isSending ) {
- NSString * filePath;
-
- // Use the tag on the UIButton to determine which image to send.
-
- filePath = [[AppDelegate sharedAppDelegate] pathForTestImage:sender.tag];
- assert(filePath != nil);
-
- [self _startSend:filePath];
- }
- }
- - (IBAction)cancelAction:(id)sender
- {
- #pragma unused(sender)
- [self _stopSendWithStatus:@"Cancelled"];
- }
- #pragma mark * View controller boilerplate
- @synthesize statusLabel = _statusLabel;
- @synthesize activityIndicator = _activityIndicator;
- @synthesize cancelButton = _stopButton;
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- assert(self.statusLabel != nil);
- assert(self.activityIndicator != nil);
- assert(self.cancelButton != nil);
-
- self.activityIndicator.hidden = YES;
- self.statusLabel.text = @"Tap a picture to start the send";
- self.cancelButton.enabled = NO;
- }
- - (void)viewDidUnload
- {
- [super viewDidUnload];
- self.statusLabel = nil;
- self.activityIndicator = nil;
- self.cancelButton = nil;
- }
- - (void)dealloc
- {
- [self _stopSendWithStatus:@"Stopped"];
- [self->_statusLabel release];
- [self->_activityIndicator release];
- [self->_stopButton release];
- [super dealloc];
- }
- @end