在swift中展开多个选项

时间:2016-01-25 11:42:16

标签: ios swift optional

我想将应用程序包中的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,则返回零。 data赋值(而不是?:运算符)是否有一些语法糖?

4 个答案:

答案 0 :(得分:3)

使用以逗号分隔的多个可选绑定

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中是不太可能的。另一个好处是能够返回非可选的PDF文档。

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!))!
}

答案 1 :(得分:0)

如果pdfPathdata为零,我假设您也不想继续执行该功能。在这种情况下,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
}

答案 2 :(得分:0)

有两种方法可以实现这一目标。

  1. 扩展NSData课程并创建您自己的convenience init?方法
  2. 使用guard声明
  3. 我更喜欢第二种方法:

    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"))
    

答案 3 :(得分:0)

你可以通过定义一个自定义运算符来处理这种情况。例如:

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)