> ## Content Index
> Fetch the complete content index at: https://williamboles.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Linting Your Podspec After Introducing Swift
- URL: https://williamboles.com/linting-your-podspec-after-introducing-swift/
- Published: 2016-03-30T12:03:41.000Z
- Updated: 2026-09-26T09:04:24.000Z
- Description: Migrating any project from Objective-C to Swift is full of pitfalls. These pitfalls exist not just in the code itself but also the supporting structure. Here, we look at one of those pitfalls related to cocoapods.
- Author: William Boles
- Tags: Cocoapods

After converting [ConvenientFileManager](https://github.com/wibosco/ConvenientFileManager?ref=williamboles.com) from an Objective-C to Swift project, I ran into the following error when linting the pod spec (`pod spec lint`):

```
-> ConvenientFileManager (2.0.0)
    - ERROR | [iOS] public_header_files: The pattern matches non-header files (ConvenientFileManager/Cache/NSFileManager+CFMCache.swift, ConvenientFileManager/Documents/NSFileManager+CFMDocuments.swift, ConvenientFileManager/Persistence/NSFileManager+CFMPersistence.swift).
    - ERROR | [iOS] xcodebuild: Returned an unsuccessful exit code. You can use `--verbose` for more information.
    - NOTE  | xcodebuild:  :1:9: note: in file included from :1:
    - ERROR | xcodebuild:  Target Support Files/ConvenientFileManager/ConvenientFileManager-umbrella.h:3:9: error: 'NSFileManager+CFMCache.swift' file not found
    - NOTE  | xcodebuild:  :0: error: could not build Objective-C module 'ConvenientFileManager'
```

#### 🤷‍♂️

Taking the advice from the above error message, I re-ran the linting in verbose mode (`--verbose`), which threw up some more information:

```
<module-includes>:1:9: note: in file included from <module-includes>:1:
#import "Headers/ConvenientFileManager-umbrella.h"
        ^
/var/folders/2v/51_f5pnn7y5dq0yz453yb4q40000gq/T/CocoaPods/Lint/Pods/Target Support Files/ConvenientFileManager/ConvenientFileManager-umbrella.h:3:9: error: 'NSFileManager+CFMCache.swift' file not found
#import "NSFileManager+CFMCache.swift"
        ^
<unknown>:0: error: could not build Objective-C module 'ConvenientFileManager'
```

After a few hours of fruitless tweaking of various project settings, I stumbled upon this [issue](https://github.com/Danappelxx/SwiftMongoDB/issues/2?ref=williamboles.com) in the Swift MongoDB project. As it turned out, this error was related to what I had in the `podspec` rather than in the project.

During the conversion to Swift, I updated the project's `podspec` to remove all references to `.h` and `.m` files by replacing them with `.swift`. This resulted in two changes:

```
s.source_files  = "ConvenientFileManager/**/*.{h,m}"
s.public_header_files = "ConvenientFileManager/**/*.{h}"
```

to

```
s.source_files  = "ConvenientFileManager/**/*.swift"
s.public_header_files = "ConvenientFileManager/**/*.swift"
```

In my haste to publish this new pod version, I didn't stop to think what `source_files` and `public_header_files` were responsible for, and this lack of understanding lay at the heart of the pod linting error.

As you can see with the original `podspec` code snippet above, `ConvenientFileManager` is exposing through the `public_header_files` configuration option, which headers are accessible when this pod is used. While not the case with `ConvenientFileManager` in some pods, there are files that are meant for internal use only, and this is where we come up against one of Objective-C's sharp edges: `access control`. Objective-C has a crude form of file access control - a header is considered public if it is externally exposed and internal if it is not. There is no way to indicate in the code if a file is `public` or `internal`; `public_header_files` is a *hack* to try and overcome this by allowing the pod creator to define a regex to control which headers are exposed.

Swift combines the header (`.h`) and implementation (`.m`) files into one file (`.swift`) and has a more sophisticated suite of [access control](https://docs.swift.org/swift-book/LanguageGuide/AccessControl.html?ref=williamboles.com) options. These improved access control options allow us to declare in code which classes should be externally accessible through the `open`, `public`, `internal`, `fileprivate` and `private` keywords. Any `internal`, `fileprivate` and `private` classes/properties/methods are stripped from the symbols list when accessed externally. This lack of headers, combined with automatic symbol stripping via in-code access controls, means that we don't need to use a regex to determine what we want and don't want to expose - the use case for the `public_header_files` configuration option doesn't exist for Swift projects.

It took a bit of digging and gaining a deeper understanding of some of the differences between Swift and Objective-C, but I eventually managed to get pod linting passing and the latest version of `ConvenientFileManager` published 😅.

For reference, this is the current `podspec` file for `ConvenientFileManager`:

```
Pod::Spec.new do |s|

  s.name         = "ConvenientFileManager"
  s.version      = "2.0.0"
  s.summary      = "A suite of categories to ease using NSFileManager for common tasks."

  s.homepage     = "http://www.williamboles.me"
  s.license      = { :type => 'MIT', 
                       :file => 'LICENSE.md' }
  s.author       = "William Boles"

  s.platform     = :ios, "9.0"

  s.source       = { :git => "https://github.com/wibosco/ConvenientFileManager.git", 
                       :branch => "master", 
                       :tag => s.version }

  s.source_files  = "ConvenientFileManager/**/*.swift"
    
  s.requires_arc = true
  
end
```