我正在尝试将Objective-C应用程序转换为swift。 我到达了需要通过FTP将文件发送到远程服务器的部分。我能够在Objective-C中实现这一点,但仅仅因为我有苹果帮助开发人员的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
(找不到重载&#39; - &#39;接受提供的参数)
说实话,我甚至不确定得到&self.buffer[self.bufferOffset]
的含义。 (不是变量,而是符号。
因此,如果有人知道如何解决这个问题,他将非常欢迎!
您可以找到SimpleFTPSample项目here。
对不起,如果我的英语不完美。
答案 0 :(得分:1)
你不能简单地将SimpleFTP编译成一个框架并直接从swift中使用它的方法吗?无需重写所有内容,Xcode为您做到了这一点。我将它用于许多自定义库,它就像一个魅力。只需添加目标,并放入所需的框架,包含框架,您就可以全部设置!
答案 1 :(得分:1)
这是我对Apple的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的项目文件。我已将其剪切以显示相关部分。
//显示我没有包含任何网络库 导入UIKit 导入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)
}