You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

iOS添加自定义日历报错EKErrorDomain Code=14(Calendar has no source)求助:为何无Local/iCloud日历源?

iOS添加自定义日历报错EKErrorDomain Code=14(Calendar has no source)求助:为何无Local/iCloud日历源?

Hi there, let's break down exactly why you're hitting this error and walk through how to fix it.

First, Why No Local/iCloud Calendar Sources?

The core problem here is your device only has read-only or restricted calendar sources right now—none of the sources you listed support creating new custom calendars. Let's unpack this:

  1. Missing iCloud Source: This happens if you haven't signed into an Apple ID with iCloud Calendar enabled, or if you toggled off the Calendar switch in Settings → [Your Name] → iCloud. iCloud sources only appear when iCloud Calendar is active for your account.
  2. Missing Local Source: iOS doesn't auto-create a Local calendar source by default. It only shows up if you've manually made a local calendar in the stock Calendar app before, or if an app has successfully written to a local calendar (which requires the source to exist first—classic catch-22!).
  3. Your Current Sources Are Unusable:
    • Subscribed calendars (type 3) are read-only—they sync from external URLs, so you can't create new calendars under this source.
    • The "Birthdays" calendar (type 4) is system-managed and locked down, so it can't be used as a parent for custom calendars either.

How to Fix the Error

We need to address two parts: getting a valid writable source, and updating your code to handle edge cases more safely.

Step 1: Get a Valid Writable Source (Manual User Fix)

First, you need to add a source that allows creating new calendars:

  • Option 1: Enable iCloud Calendar: Go to Settings → [Your Name] → iCloud and toggle on the Calendar switch. This will add an iCloud source to your device, which fully supports custom calendar creation.
  • Option 2: Create a Local Calendar: Open the stock Calendar app → Tap "Calendars" at the bottom → Scroll to the very end and tap "Add Calendar" → Select "Local", name it, and save. This will generate a Local source your code can use.

Step 2: Update Your Code to Handle Edge Cases

Your current code falls back to defaultCalendarForNewEvents.source, but that source might be read-only (like your subscribed holiday calendars). Let's adjust the code to properly find writable sources, and fail gracefully if none exist:

EKCalendar *customCalendar = [EKCalendar calendarForEntityType:EKEntityTypeEvent eventStore:eventStore];
customCalendar.CGColor = UIColor.blueColor.CGColor;

EKSource *selectedSource = nil;
NSArray<EKSource *> *sources = eventStore.sources;

// 1. First search for writable Local or iCloud sources
for (EKSource *source in sources) {
    BOOL isSupportedType = (source.sourceType == EKSourceTypeLocal || 
                           (source.sourceType == EKSourceTypeCalDAV && [source.title.lowercaseString containsString:@"icloud"]));
    BOOL canWrite = [source allowsContentModifications];
    
    if (isSupportedType && canWrite) {
        selectedSource = source;
        break;
    }
}

// 2. If no Local/iCloud, look for any other writable source as a backup
if (!selectedSource) {
    for (EKSource *source in sources) {
        if ([source allowsContentModifications]) {
            selectedSource = source;
            break;
        }
    }
}

// 3. If still no valid source, prompt the user to fix their settings
if (!selectedSource) {
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"无法创建日历"
                                                                   message:@"请前往「设置」开启iCloud日历,或在系统日历App中创建一个本地日历后重试。"
                                                            preferredStyle:UIAlertControllerStyleAlert];
    [alert addAction:[UIAlertAction actionWithTitle:@"知道了" style:UIAlertActionStyleDefault handler:nil]];
    // Make sure to present this alert from a valid view controller context
    [self presentViewController:alert animated:YES completion:nil];
    return;
}

// Assign the valid source and attempt to save
customCalendar.source = selectedSource;
NSError *error = nil;
BOOL saveSuccess = [eventStore saveCalendar:customCalendar commit:YES error:&error];

if (!saveSuccess) {
    NSLog(@"保存日历失败: %@", error.localizedDescription);
    // Add user-facing error feedback here, like another alert
}

Key Notes to Remember

  • Always check allowsContentModifications before using a source—this filters out read-only sources like subscriptions or system calendars.
  • Relying on defaultCalendarForNewEvents is risky because it might point to a read-only source (like your subscribed holidays), which will still cause a save failure.
  • Double-check that you've added the NSCalendarsUsageDescription permission to your Info.plist (required for iOS 10+), though this isn't the root issue here since you can already access the source list.

Let me know if you need help troubleshooting any of these steps further! 😊

火山引擎 最新活动