4

我正在尝试将 Objective-C 应用程序转换为 swift。我到达了需要通过 FTP 将文件发送到远程服务器的部分。我能够在 Objective-C 中做到这一点,但这只是因为我有Apple 为帮助开发人员而制作的SimpleFTPSample项目。现在我几乎完成了两种语言之间的转换,但我被卡住了。

我需要转换该代码(来自 SimpleFTPSample+personal):

- (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;
    }
}

现在我设法做到了:

// An NSStream delegate callback that's called when events happen on our
// network stream.
func stream(theStream: NSStream!, handleEvent streamEvent: NSStreamEvent) {
    switch (streamEvent) {
    case NSStreamEvent.OpenCompleted:
        println("Opened connection")
    case NSStreamEvent.HasBytesAvailable:
        println("Not suposed to happend")
    case NSStreamEvent.HasSpaceAvailable:
        println("Sending")

        // If we don't have any data buffered, go read the next chunk of data.
        if self.bufferOffset == self.bufferLimit {
            var bytesRead: Int
            bytesRead = self.fileStream.read(self.buffer, maxLength: 32768)

            if bytesRead == -1 { self.stopSendWithStatus("File read error") }
            else if bytesRead == 0 { self.stopSendWithStatus(nil) }
            else {
                self.bufferOffset = 0
                self.bufferLimit  = size_t(bytesRead)
            }
        }

        // If we're not out of data completely, send the next chunk.
        if self.bufferOffset != self.bufferLimit {
            var bytesWritten: Int

            bytesWritten = self.networkStream.write(&self.buffer[self.bufferOffset], maxLength: self.bufferLimit - self.bufferOffset)

            if bytesWritten == -1 { self.stopSendWithStatus("Network write error") }
            else { self.bufferOffset += size_t(bytesWritten) }
        }
    case NSStreamEvent.ErrorOccurred:
        self.stopSendWithStatus("Stream open error")
    case NSStreamEvent.EndEncountered:
        println("ignore")
    default:
        println("default")
    }
}

使用的变量的种类是:

var isSending = Bool()
var networkStream: NSOutputStream! = NSOutputStream()
var fileStream: NSInputStream! = NSInputStream()
var buffer: CConstPointer<UInt8>
var bufferOffset = size_t()
var bufferLimit = size_t()

我被困住了if self.bufferOffset != self.bufferLimit

显然&self.buffer[self.bufferOffset]是不正确的(没有成员名称下标),以及self.bufferLimit - self.bufferOffset(找不到接受提供的参数的重载'-')

老实说,我什至不确定得到什么&self.buffer[self.bufferOffset]意思。(不是变量,而是符号。

因此,如果有人对如何解决这个问题有任何想法,他将非常受欢迎!

您可以在此处找到 SimpleFTPSample 项目。

对不起,如果我的英语不完美。

4

2 回答 2

1

你不能直接将 SimpleFTP 编译成一个框架并直接从 swift 中使用它的方法吗?无需重写所有内容,Xcode 为您完成。我将它用于许多自定义库,它就像一个魅力。只需添加目标,并放入所需的框架,包括框架,一切就绪!

于 2014-06-09T09:32:19.487 回答
1

这是我抄袭苹果的 SimpleFTPExample 以解决我将 csv 文件从 iOS 应用程序上传到 ftp 服务器的问题。我取出了 PutController Objective-c 文件,从中删减了很多(太多了?),并将其包含在我的 swift 应用程序中。我修改了传递给主 PutController 函数的参数,以传递我想要发送的数据、它必须去的 URL 以及进入服务器的用户名和密码。

删减的 PutController.m

#import "PutController.h"
#include <CFNetwork/CFNetwork.h>

enum {
    kSendBufferSize = 32768
};

@interface PutController () <NSStreamDelegate>

@property (nonatomic, strong, readwrite) NSOutputStream *  networkStream;
@property (nonatomic, strong, readwrite) NSInputStream *   fileStream;
@property (nonatomic, assign, readonly ) uint8_t *         buffer;
@property (nonatomic, assign, readwrite) size_t            bufferOffset;
@property (nonatomic, assign, readwrite) size_t            bufferLimit;

@end

@implementation PutController
{
    uint8_t _buffer[kSendBufferSize];
}

// 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;
}


- (void)startSend:(NSData *)dataToUpload withURL:(NSURL *)toURL withUsername:(NSString *)username andPassword:(NSString *)password
{
    printf(__FUNCTION__);

    self.fileStream = [NSInputStream inputStreamWithData:dataToUpload];

    [self.fileStream open];

    // Open a CFFTPStream for the URL.

    self.networkStream = CFBridgingRelease(
        CFWriteStreamCreateWithFTPURL(NULL, (__bridge CFURLRef) toURL)
    );

    [self.networkStream setProperty:username forKey:(id)kCFStreamPropertyFTPUserName];
    [self.networkStream setProperty:password forKey:(id)kCFStreamPropertyFTPPassword];

    self.networkStream.delegate = self;
    [self.networkStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [self.networkStream open];

}

- (void)stopSendWithStatus:(NSString *)statusString
{
    printf(__FUNCTION__);

    if (self.networkStream != nil) {
        [self.networkStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        self.networkStream.delegate = nil;
        [self.networkStream close];
        self.networkStream = nil;
    }
    if (self.fileStream != nil) {
        [self.fileStream close];
        self.fileStream = nil;
    }
}

- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
    // An NSStream delegate callback that's called when events happen on our 
    // network stream.
{
    printf(__FUNCTION__);

    switch (eventCode) {
        case NSStreamEventOpenCompleted: {
            printf("Opened connection");
        } break;
        case NSStreamEventHasBytesAvailable: {
            printf("should never happen for the output stream");
        } break;
        case NSStreamEventHasSpaceAvailable: {
            printf("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;
    }
}

@end

然后是 PutController.h

#import <UIKit/UIKit.h>

@interface PutController : NSObject

- (void)startSend:(NSData *)dataToUpload withURL:(NSURL *)toURL withUsername:(NSString *)username andPassword:(NSString *)password;
@end

这是项目范围的桥接文件,允许 swift 应用程序获取 Objective-C 头文件。Objective-C 的代码细节大部分可以被忽略。真的是一条线。

// PlantRoomChecks-Bridging-Header.h
//
//  Use this file to import your target's public headers that you would like to expose to Swift.
//
#import "PutController.h"

这是我调用 PutController 的项目文件。我已将其剪切以仅显示相关部分。

// 显示我没有包含任何网络库 import UIKit import CoreGraphics

类 GraphVC: UIViewController {

var sendFile : PutController = PutController()

let username = "arthur_dent"
let password = "six_times_seven"


func saveData(){

    var filename = "ftp://www.domain.co.uk/subdirectory/datafile"

    // Converting the messing filename into one that can be used as a URL
    let convertedStringForURL = filename.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
    let uploadUrl = NSURL(string: convertedStringForURL!)

    Let dataForFile : NSData = dataFromElseWhere
    let dataToUpload = dataForFile.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)

    // USE THE OBJECTIVE-C VARIABLE
    sendFile.startSend(dataToUpload, withURL: uploadUrl, withUsername: username, andPassword: password)

}
于 2014-12-10T13:07:36.010 回答