#pragma mark with special comment tokens recognized by Xcode: use // MARK: Section Name to group methods in the jump bar, or // MARK: - Section Name to prefix the label with a horizontal separator line. You can also use // TODO: and // FIXME: to highlight pending work.Why this happens
In Objective-C, #pragma mark is a compiler directive parsed by the C preprocessor. Developers historically used it to inject visual section breaks and bold headers into Xcode’s jump bar, making large files easier to navigate.
Swift does not include a C-style preprocessor. Directives like #pragma are not recognized by the Swift compiler, causing #pragma mark lines to be rejected or ignored.
To preserve code organization within Xcode, Apple introduced comment-based annotations. Xcode’s indexing engine scans Swift files for standardized comment tokens—specifically // MARK:, // TODO:, and // FIXME:—and renders them into the editor jump bar, the symbol navigator, and the source code minimap.
How to fix it
1. Replace #pragma mark with // MARK:
Xcode parses // MARK: comments to generate headings in the jump bar (which you can open quickly in any source file using the keyboard shortcut Control-6).
You can format these annotations in three ways depending on the visual hierarchy you need:
- Header only: Creates a bold text label in the jump bar.
- Header with divider line: Inserts a horizontal separator rule above the bold text label.
- Divider line only: Inserts a separator rule without any text label.
Here is how each format looks in code:
import UIKit
final class ProfileViewController: UIViewController {
// MARK: - Properties
private let avatarImageView = UIImageView()
private let usernameLabel = UILabel()
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
setupSubviews()
loadUserData()
}
// MARK: -
// MARK: Setup Methods
private func setupSubviews() {
view.addSubview(avatarImageView)
view.addSubview(usernameLabel)
}
private func loadUserData() {
// Fetch profile data
}
}
Formatting Rules for Xcode Parsing:
* A space is required between the slashes and MARK:: // MARK: works, while //MARK: is inconsistent across older Xcode toolchains.
* The colon : immediately after MARK is mandatory.
* Adding a hyphen and a space after the colon (// MARK: - Heading) places a horizontal line directly above the heading in the symbol jump bar.
2. Highlight Tasks with // TODO: and // FIXME:
Xcode also parses // TODO: and // FIXME: tags and displays them with distinctive icons in the jump bar and minimap:
// TODO: [Note]indicates work planned for a future commit.// FIXME: [Note]flags broken logic or a temporary workaround that needs immediate review.
final class NetworkManager {
func authenticateUser(token: String) {
// TODO: Replace hardcoded timeout with remote configuration value
let timeoutInterval: TimeInterval = 30.0
// FIXME: Handle token expiration refresh instead of failing silently
guard !token.isEmpty else {
return
}
}
}
These annotations appear in the jump bar alongside your MARK groups, helping you track outstanding technical debt directly within your source code.
3. Pair // MARK: with Swift Extensions
In Objective-C, #pragma mark was frequently required because class implementations, protocol conformances, and helper utilities lived in a single continuous @implementation block.
In Swift, the best architectural pattern is to split protocol conformances and functional domains into explicit extension blocks, using // MARK: - comments to identify them. This provides semantic separation at both the compiler level and the jump bar level:
import UIKit
final class ArticleListViewController: UIViewController {
private let tableView = UITableView()
private var articles: [String] = []
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
}
}
// MARK: - UITableViewDataSource
extension ArticleListViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return articles.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ArticleCell", for: indexPath)
cell.textLabel?.text = articles[indexPath.row]
return cell
}
}
// MARK: - UITableViewDelegate
extension ArticleListViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
}
}
By placing each protocol conformance in its own extension, you make methods easier to locate and reduce the cognitive overhead of reading large view controllers or view models.
How to prevent it
- Use Xcode code snippets: Create a custom code snippet in Xcode for
// MARK: - <#Section#>mapped to a shortcut likemarkto ensure uniform spacing and colons. - Enforce formatting with SwiftLint: Add rules like
markandtodoto your.swiftlint.ymlconfiguration to ensure developers consistently format comments and resolve abandoned tags. - Separate by extensions first: Prefer moving delegate conformances, private helper routines, and previews into dedicated extensions rather than stacking all code inside the main type body.
FAQ
Does // MARK: show up in the Xcode minimap?
Yes. Xcode automatically renders // MARK: annotations as visible section titles inside the source editor’s minimap on the right-hand side of the code window. Hovering over a mark in the minimap highlights the corresponding block of code.
Why is my // MARK: comment not showing in the jump bar?
This usually happens when the required colon or spacing is missing. The format must be // MARK: Description or // MARK: - Description. If the colon is omitted (e.g., // MARK Description), Xcode treats the line as a standard comment and skips it.
Can I use #pragma mark in mixed Swift and Objective-C projects?
You can continue using #pragma mark in .m and .mm Objective-C implementation files within your project. However, any .swift files in that same project must use // MARK: because the Swift compiler does not recognize C preprocessor directives.
Parts of this guide are adapted from content licensed under CC BY-SA 4.0; this article is shared under the same license.
