Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsCommunityBlog
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Authors
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

ProTermsPrivacyRefunds
Back to skills

Contacts Framework

ASecurity

Read, create, update, and pick contacts using the Contacts and ContactsUI frameworks. Use when fetching contact data, saving new contacts, wrapping CNContactPickerViewController in SwiftUI, handling contact permissions, or working with CNContactStore fetch and save requests.

3 stars
0 votes
0 copies
0 views
Added 9/28/2026
developmentswiftapidocumentation

Works with

api

Security Analysis

A100/100

Scanned 9/28/2026

Install to Claude Code

$npx -y skills add thiennc-tesoglobal/ios-skills --skill contacts-framework --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Contacts Framework?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Contacts Framework
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/thiennc-tesoglobal-contacts-framework/badge)](https://www.skillsdirectory.com/skills/thiennc-tesoglobal-contacts-framework)

More formats (shields.io, HTML) on the badges page.

Files
SKILL.md
---
name: contacts-framework
description: "Read, create, update, and pick contacts using the Contacts and ContactsUI frameworks. Use when fetching contact data, saving new contacts, wrapping CNContactPickerViewController in SwiftUI, handling contact permissions, or working with CNContactStore fetch and save requests."
---

# Contacts Framework

Use `CNContactStore`, `CNSaveRequest`, and ContactsUI to fetch, mutate, or let
the user select contacts. Prefer the system picker when full address-book access
is unnecessary.

## Contents

- [Choose the access model](#choose-the-access-model)
- [Setup and authorization](#setup-and-authorization)
- [Fetch invariants](#fetch-invariants)
- [Mutation invariants](#mutation-invariants)
- [Concurrency and cache invalidation](#concurrency-and-cache-invalidation)
- [Common mistakes](#common-mistakes)
- [Review checklist](#review-checklist)
- [References](#references)

## Choose the access model

| Need | API |
|---|---|
| User chooses one or more contacts without broad permission | `CNContactPickerViewController` |
| App reads or writes its authorized contact set | `CNContactStore` |
| User expands an iOS 18+ limited set | `ContactAccessButton` or `contactAccessPicker` |
| Import/export or sharing | `CNContactVCardSerialization` |

Read [Contacts extended patterns](references/contacts-patterns.md) for a complete
observable manager, SwiftUI lists, single/multi-select picker wrappers,
email-only selection, optimized search, vCard import/export, groups, and change
notification handling.

## Setup and authorization

- Add `NSContactsUsageDescription` before direct Contacts API access; missing it
  causes termination.
- Ordinary access needs no entitlement. Reading or writing `CNContact.note`
  requires the Apple-approved `com.apple.developer.contacts.notes` entitlement.
- The system contact picker does not require broad Contacts authorization; the
  app receives only selected data.

Treat authorization states explicitly:

| Status | Behavior |
|---|---|
| `.notDetermined` | Request only from a user-understood action |
| `.authorized` | Full access |
| `.limited` | Usable, but only for granted or app-created contacts |
| `.denied` | Explain the feature and route to Settings when appropriate |
| `.restricted` | Disable the operation; do not repeatedly prompt |

## Fetch invariants

Only fetch keys the caller will access. Reading an unfetched property raises
`CNContactPropertyNotFetchedException`.

```swift
@preconcurrency import Contacts

let keys: [CNKeyDescriptor] = [
    CNContactFormatter.descriptorForRequiredKeys(for: .fullName),
    CNContactPhoneNumbersKey as CNKeyDescriptor
]

let request = CNContactFetchRequest(keysToFetch: keys)
try store.enumerateContacts(with: request) { contact, stop in
    consume(contact)
}
```

Use `unifiedContacts(matching:keysToFetch:)` for predicate queries,
`unifiedContact(withIdentifier:keysToFetch:)` for known identifiers, and
enumeration for the authorized address book. Avoid full-resolution image data
unless the UI truly requires it. For large caches, fetch identifiers first and
hydrate details in bounded batches.

## Mutation invariants

- Create with `CNMutableContact` and `CNSaveRequest.add`.
- Update or delete by fetching the required properties, creating
  `mutableCopy()`, then adding the operation to a fresh save request.
- `store.execute(request)` returning without throwing is the success boundary.
  Advance app state or clear drafts only afterward.
- On failure, preserve the user's intent, surface the error, correct known
  authorization/container/input causes, refetch stale contacts when possible,
  and construct a new request. Do not blindly replay a destructive request.
- Serialize overlapping saves and never mutate a request while `execute` uses it.

```swift
let mutable = CNMutableContact()
mutable.givenName = "Taylor"

let request = CNSaveRequest()
request.add(mutable, toContainerWithIdentifier: nil)
try store.execute(request)
```

## Concurrency and cache invalidation

Enumeration is I/O-heavy; keep it off the main actor. With strict concurrency,
use `@preconcurrency import Contacts` only at the framework boundary or map
`CNContact` values into app-owned `Sendable` models before crossing actors.

Observe `.CNContactStoreDidChange`, invalidate cached `CNContact` objects, and
refetch the authorized set. Reuse one store instead of constructing stores per
row or query.

## Common Mistakes

- Requesting full access when a picker satisfies the feature.
- Treating `.limited` as denial or assuming it exposes the full address book.
- Fetching every key, especially full image data.
- Accessing a property not included in `keysToFetch`.
- Attempting to mutate immutable `CNContact` directly.
- Updating UI/cache before `execute` succeeds.
- Enumerating contacts on the main actor or retaining stale contact objects.

## Review Checklist

- [ ] Usage description and note entitlement requirements are correct.
- [ ] Picker is preferred when broad access is unnecessary.
- [ ] Every authorization state, including `.limited`, has product behavior.
- [ ] Fetch descriptors include exactly the accessed properties.
- [ ] Name formatting uses the formatter's required-key descriptor.
- [ ] Create/update/delete use fresh `CNSaveRequest` values and mutable contacts.
- [ ] App state changes only after a successful save; failures preserve intent.
- [ ] Heavy reads run off the main actor and cross actors safely.
- [ ] Store-change notification invalidates and refetches caches.
- [ ] One long-lived `CNContactStore` is reused.

## References

- [Contacts extended patterns](references/contacts-patterns.md)
- [Contacts documentation](https://sosumi.ai/documentation/contacts)
- [CNContactStore](https://sosumi.ai/documentation/contacts/cncontactstore)
- [CNSaveRequest](https://sosumi.ai/documentation/contacts/cnsaverequest)
- [CNContactPickerViewController](https://sosumi.ai/documentation/contactsui/cncontactpickerviewcontroller)
- [Contact access controls](https://sosumi.ai/documentation/contactsui/contactaccessbutton)

Attribution

thiennc-tesoglobalthiennc-tesoglobal
View sourceMore from thiennc-tesoglobal →
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

Browser Extension Developer

Use this skill when developing or maintaining browser extension code in the `browser/` directory, including Chrome/Firefox/Edge compatibility, content scripts, background scripts, or i18n updates.

284972 votes

Seo Optimizer

SEO optimization with keyword analysis, readability assessment, technical validation, content quality. Use for search rankings, blog posts, content audits, or encountering keyword density, readability scores, meta tags, schema markup errors.

2222 votes

Google Official Seo Guide

Official Google SEO guide covering search optimization, best practices, Search Console, crawling, indexing, and improving website search visibility based on official Google documentation

1862 votes

Tanstack Start

Build a full-stack TanStack Start app on Cloudflare Workers from scratch — SSR, file-based routing, server functions, D1+Drizzle, better-auth, Tailwind v4+shadcn/ui. Use whenever the user mentions TanStack Start, asks to scaffold a full-stack Cloudflare app with SSR, wants an SSR dashboard, or asks for a React 19 + Cloudflare Workers app with file-based routing and server functions — even if they don't name TanStack Start specifically. No template repo — Claude generates every file fresh per ...

10311 votes

Pentest

PTES-aligned adversarial security audit for backend, frontend, and mobile applications. Produces a CVSS-scored Hacker Report with verified PoCs and phased remediation.

5491 votes
View all in development →