Swift fileprivate vs private

2024-02-22
#swift

fileprivateprivate 主要区别在于作用域,对于 fileprivate 修饰的变量,只要在变量声明的所在的文件这个变量都可以被访问到;而 private 则只可以在它声明的对象里被访问到,比如 classstruct

例子

  // A.swift
  struct A {
        private var privateVar = 0  
        fileprivate var fileprivateVar = 1  
    }

这个例子下,显然 privateVarfileprivateVar 都可以被访问到,这个时候我们在 A.swift 文件里再创建一个 struct NotA

  // A.swift
  struct NotA {
      let a: A
      func readOutsideA() {
         	// 变量 privateVar 无法被访问
          print(a.privateVar)
          // 变量 fileprivateVar 依旧可以访问到 
          print(a.fileprivateVar)
      }
  }

显然如果我们尝试在别的文件里去访问上面两个变量,结果都是无法访问的。

使用场景

对于 private 来说,私有变量通常就是为了在对象内部使用的,用来隐藏对象内部的一些复杂性或者信息的,凡是能使用 private 都可以使用fileprivate,有没有必须使用 fileprivate 的场景呢?就和上述的例子一样,需要在同一个文件下,一个对象需要访问另外一个对象的变量,而又不像这个变量被其他文件下的对象使用

fileprivate

  // 代码来源:
  // https://github.com/mangerlahn/Latest/blob/1d5a0ae844bbf6ffb93f5efbac8fab55eac59030/Latest/Model/AppLibrary.swift#L192
  // AppLibrary.swift
  fileprivate extension Bundle {
  	
  	/// Returns the bundle version which is guaranteed to be current.
  	var uncachedBundleVersion: String? {
  		let bundleRef = CFBundleCreate(.none, self.bundleURL as CFURL)
  		
  		// (NS)Bundle has a cache for (all?) properties, presumably to reduce disk access. Therefore, after updating an app, the old bundle version may be
  		// returned. Flushing the cache (private method) resolves this.
  		_CFBundleFlushBundleCaches(bundleRef)
  		
  		return infoDictionary?["CFBundleVersion"] as? String
  	}
  
  	/// Returns the bundle name when working without Spotlight.
  	var bundleName: String? {
  		return infoDictionary?["CFBundleName"] as? String
  	}
  
  	/// Returns the short version string when working without Spotlight.
  	var versionNumber: String? {
  		return infoDictionary?["CFBundleShortVersionString"] as? String
  	}
  }

作者使用 fileprivateBundle 进行拓展,但是由于这些方法并不被其他使用 Bundle 的文件使用到,所以就使用了 fileprivate 来进行修饰,本身这些方法如果放在原有的类做成方法封装也是可以的,不过感觉作者使用 fileprivate 这种做法,让原本不属于类的方法剥离出来,显得更简洁优雅一些,不过这都是我个人看法,实际使用就取决自己了。

参考链接