Развертывание нескольких опций в swift
Я хочу загрузить PDF, который находится в моем комплекте приложений, в CGPDFDocument.
Есть ли способ вызова функции, если любой из параметров, которые не принимают параметры, имеет значения, равные nil, функция не вызывается и возвращается nil.
например:
let pdfPath : String? = NSBundle.mainBundle().pathForResouce("nac_06", ofType:"pdf")
//I want to do this
let data : NSData? = NSData(contentsOfFile:pdfPath)
//I have to do this
let data : NSData? = pdfPath != nil ? NSData(contentsOfFile:pdfPath) : nil
let doc : CGPDFDocumentRef? = CGPDFDocumentCreateWithProvider(CGDataProviderCreateWithCFData(data));
//pageView.pdf is optional, nicely this function accepts the document as an optional
pageView.pdfPage = CGPDFDocumentGetPage(doc, 1);
Поскольку NSData.init?(ContentsOfFile path:String), не определяет path
как необязательный, даже если он имеет необязательное возвращаемое значение, я должен проверить раньше, и если параметр равен nil, вернуть nil. Есть ли синтаксический сахар для data
назначение (вместо ?:
оператор)?
4 ответа
Либо используйте несколько необязательных привязок, разделенных запятыми
func loadPDF() -> CGPDFDocumentRef?
{
if let pdfPath = NSBundle.mainBundle().pathForResouce("nac_06", ofType:"pdf"),
data = NSData(contentsOfFile:pdfPath),
doc = GPDFDocumentCreateWithProvider(CGDataProviderCreateWithCFData(data)) {
return doc
} else {
return nil
}
}
или используйте guard
заявление
func loadPDF() -> CGPDFDocumentRef?
{
guard let pdfPath = NSBundle.mainBundle().pathForResouce("nac_06", ofType:"pdf") else { return nil }
guard let data = NSData(contentsOfFile:pdfPath) else { return nil }
return GPDFDocumentCreateWithProvider(CGDataProviderCreateWithCFData(data))
}
Все явные аннотации типов являются синтаксическим сахаром и не нужны.
Редактировать:
В вашем конкретном случае вам нужно только проверить, существует ли файл, и даже это - файл отсутствует - очень маловероятно в iOS. Еще одним преимуществом является возможность вернуть необязательный PDFDocument.
func loadPDF() -> CGPDFDocumentRef
{
guard let pdfPath = NSBundle.mainBundle().pathForResource("nac_06", ofType:"pdf") else {
fatalError("file nac_06.pdf does not exist")
}
let data = NSData(contentsOfFile:pdfPath)
return CGPDFDocumentCreateWithProvider(CGDataProviderCreateWithCFData(data!))!
}
Есть два способа добиться этого.
- простираться
NSData
класс и создать свой собственныйconvenience init?
метод - Использовать
guard
заявление
Я предпочитаю второй метод:
func getPDF(path : String?) -> CGPDFDocumentRef?
{
guard let filePath = path,
data = NSData(contentsOfFile: filePath),
pdf = GPDFDocumentCreateWithProvider(CGDataProviderCreateWithCFData(data)) else
{
return nil
}
return pdf
}
Вызовите метод как:
let doc = getPDF(path : NSBundle.mainBundle().pathForResouce("nac_06", ofType:"pdf"))
Вы можете сделать что-то необычное, определив пользовательский оператор для решения этой ситуации. Например:
infix operator ^> {associativity left precedence 150}
func ^><T, U>(arg: T?, f: T->U?) -> U?{
if let arg = arg {
return f(arg)
} else {
return nil
}
}
Оператор принимает необязательный аргумент левой стороны и функцию, которая принимает необязательный аргумент и возвращает другой необязательный аргумент в качестве аргумента правой стороны.
Затем вы можете написать свой код так:
let pdfPath = NSBundle.mainBundle().pathForResource("nac_06", ofType:"pdf")
//the line below needs a NSData extension
let data = pdfPath ^> NSData.fileContents
let doc = data ^> CGDataProviderCreateWithCFData ^> CGPDFDocumentCreateWithProvider
//pageView.pdf is optional, nicely this function accepts the document as an optional
pageView.pdfPage = CGPDFDocumentGetPage(doc, 1)
Обратите внимание, что для этого вам нужно добавить расширение к NSData, так как вы не можете отобразить init(contentsOfFile:)
инициализатор для универсальной функции, которая может быть передана ^>
,
extension NSData {
class func fileContents(path: String) -> NSData? {
return NSData(contentsOfFile: path)
}
}
Использование ^>
Оператор, однако, восстанавливает порядок, в котором вы пишете имена функций. Если вы предпочитаете, чтобы имена функций были в том же порядке, что и исходный код, вы можете добавить обратный оператор, который делает то же самое:
infix operator ^< {associativity right precedence 150}
func ^< <T, U>(f: T->U?, arg: T?) -> U?{
if let arg = arg {
return f(arg)
} else {
return nil
}
}
let pdfPath = NSBundle.mainBundle().pathForResource("nac_06", ofType:"pdf")
let data = NSData.fileContents ^< pdfPath
let doc = CGPDFDocumentCreateWithProvider ^< CGDataProviderCreateWithCFData ^< data
//pageView.pdf is optional, nicely this function accepts the document as an optional
pageView.pdfPage = CGPDFDocumentGetPage(doc, 1)
Я предполагаю, что вы также не хотите продолжать выполнение функции, если pdfPath
или же data
ноль В этом случае, guard
будет лучшим выбором:
guard let pdfPath = NSBundle.mainBundle().pathForResouce("nac_06", ofType:"pdf") else {
// eventually also report some error
return
}
guard let data = NSData(contentsOfFile:pdfPath) else {
// eventually also report some error
return
}
// at this point you have a valid data object
Вы также можете объединить это в один guard
утверждение, чтобы уменьшить дублирование кода, вы потеряете, однако, в этом случае возможность узнать, какой из двух не удалось.
guard let pdfPath = NSBundle.mainBundle().pathForResource("nac_06", ofType:"pdf"),
data = NSData(contentsOfFile:pdfPath) else {
// eventually also report some error
return
}