iOS日历中的日程生成VCalendar 2.0(.vcs)格式的字符串和解析

2023-05-16

// 获取 VCalendar2.0 的格式字符串
+ (NSString *)getVCalendar20StrWithEvents:(NSArray<EKEvent *> *)events {
    NSString *vcalendar = [NSString stringWithFormat:@"X-SIZE:%lu\n", (unsigned long)events.count];
    
    //版本头
    vcalendar = [vcalendar stringByAppendingString:@"BEGIN:VCALENDAR\nVERSION:2.0\nPRODID:-//STKJ//iOS//EN\n"];
    
    NSString *formatterStr = @"yyyyMMdd HHmmss";
    NSDate *currentDate = [[NSDate alloc] init];
    NSString *currentDateStr = [NSDate stringFromDate:currentDate andFormatterString:formatterStr];
    currentDateStr = [currentDateStr stringByReplacingOccurrencesOfString:@" " withString:@"T"];
    currentDateStr = [currentDateStr stringByAppendingString:@"Z"];
   vcalendar = [vcalendar stringByAppendingFormat:@"BEGIN:VTIMEZONE\nTZID:UTC\nBEGIN:STANDARD\nDTSTART:%@\nTZOFFSETFROM:+0800\nTZOFFSETTO:+0800\nEND:STANDARD\nBEGIN:DAYLIGHT\nDTSTART:%@\nTZOFFSETFROM:+0800\nTZOFFSETTO:+0800\nEND:DAYLIGHT\nEND:VTIMEZONE\n", currentDateStr, currentDateStr];
    
    for(CFIndex i = 0; i < events.count; i++) {
        EKEvent *event = events[i];
        NSString *title = event.title;
        title = title == nil ? @"" : title;
        NSString *notes = event.notes;
        notes = notes == nil ? @"" : notes;
//        NSString *location = event.location;
        NSURL *url = event.URL;
//        NSDate *lastModifiedDate = event.lastModifiedDate;
//        NSDate *creationDate = event.creationDate;
        NSDate *startDate = event.startDate;
        startDate = startDate == nil ? [[NSDate alloc] init] : startDate;
        NSDate *endDate = event.endDate;
        endDate = endDate == nil ? [[NSDate alloc] init] : endDate;
//        NSTimeZone *timeZone = event.timeZone;
        
        // 编码
        title = [NSString URLencode:title stringEncoding:NSUTF8StringEncoding];
        title = [title stringByReplacingOccurrencesOfString:@"%" withString:@"="];
        notes = [NSString URLencode:notes stringEncoding:NSUTF8StringEncoding];
        notes = [notes stringByReplacingOccurrencesOfString:@"%" withString:@"="];
        
        // 开始时间
        NSString *startDateStr = [NSDate stringFromDate:startDate andFormatterString:formatterStr];
        startDateStr = [startDateStr stringByReplacingOccurrencesOfString:@" " withString:@"T"];
        startDateStr = [startDateStr stringByAppendingString:@"Z"];
        // 结束时间
        NSString *endDateStr = [NSDate stringFromDate:endDate andFormatterString:formatterStr];
        endDateStr = [endDateStr stringByReplacingOccurrencesOfString:@" " withString:@"T"];
        endDateStr = [endDateStr stringByAppendingString:@"Z"];
        vcalendar = [vcalendar stringByAppendingFormat:@"BEGIN:VEVENT\nDESCRIPTION;ENCODING=QUOTED-PRINTABLE;CHARSET=UTF-8:%@\nDTEND:%@\nDTSTAMP:%@\nX-ALLDAY:0\nDTSTART:%@\n", title, endDateStr, startDateStr, startDateStr];
        
        // url
        if (url != nil) {
            vcalendar = [vcalendar stringByAppendingFormat:@"UID: %@\n", url.absoluteString];
        }
        
        // 笔记
        if (event.hasNotes) {
            vcalendar = [vcalendar stringByAppendingFormat:@"SUMMARY;ENCODING=QUOTED-PRINTABLE;CHARSET=UTF-8:%@\nX-ALLDAY:0\nSTATUS:CONFIRMED\n", notes];
        }
        
        // 是否有提醒
        if (event.hasAlarms) {
            for (EKAlarm *alarm in event.alarms) {
                if (alarm != nil) {
                    vcalendar = [vcalendar stringByAppendingFormat:@"BEGIN:VALARM\nACTION:AUDIO\nTRIGGER:-PT10M\nEND:VALARM\n"];
                }
            }
                
        }
        
        if (event.hasAttendees) {
            
        }
        
        if (event.hasRecurrenceRules) {
            
        }
        
        vcalendar = [vcalendar stringByAppendingFormat:@"END:VEVENT\n"];
    }
    vcalendar = [vcalendar stringByAppendingString:@"END:VCALENDAR"];
    
    return vcalendar;
}

 

// 解析 VCalendar2.0 的格式字符串
+ (NSArray<EKEvent *> *)parseVCalendar20StrWithEvents:(NSString *)vcalendarStr andEventStore:(EKEventStore *)store {
    NSString *SeparatedStr1 = @":";
    NSString *SeparatedStr2 = @"\n";
    BOOL isIn = false;
    
    // head data
    NSInteger count = 0;
    NSInteger index = 0;
    NSString *timeCode = @"UTC";
    NSString *tzoffsetFrom = @"";
    
    NSArray *lines = [vcalendarStr componentsSeparatedByString:SeparatedStr2];
    // 获取count
    if (lines.count > 0) {
        if ([lines[0] hasPrefix:@"X-SIZE"]) {
            NSArray *dataArray = [lines[0] componentsSeparatedByString:SeparatedStr1];
            count = [dataArray[1] integerValue];
        } else {
            NSLog(@"缺少X-SIZE字段");
            return nil;
        }
    } else {
        NSLog(@"字符中没有换行或为空");
        return nil;
    }
    
    // 创建事件
    NSMutableArray<EKEvent *> *eventsArray = [[NSMutableArray alloc] initWithCapacity:count];
    for (int i = 0; i < count; i++) {
        EKEvent *event = [EKEvent eventWithEventStore:store];
        [eventsArray addObject:event];
    }
    
    for(NSString* line in lines) {
        if ([line hasPrefix:@"BEGIN:VCALENDAR"]) {
            NSLog(@"parse start");
        } else if ([line hasPrefix:@"END:VCALENDAR"]) {
            NSLog(@"parse end");
        } else if ([line hasPrefix:@"TZID"]) {
            NSArray *dataArray = [line componentsSeparatedByString:SeparatedStr1];
            timeCode = dataArray[1];
        } else if ([line hasPrefix:@"TZOFFSETFROM"]) {
            NSArray *dataArray = [line componentsSeparatedByString:SeparatedStr1];
            tzoffsetFrom = dataArray[1];
        } else if (isIn || [line hasPrefix:@"BEGIN:VEVENT"]) {
            isIn = true; // 进入位
            
            EKEvent *event = [eventsArray objectAtIndex:index];
            if ([line hasPrefix:@"SUMMARY"]) {
                NSArray *dataArray = [line componentsSeparatedByString:SeparatedStr1];
                // 解码
                NSString *text = [dataArray[1] stringByReplacingOccurrencesOfString:@"=" withString:@"%"];
                text = [NSString URLdecode:text stringEncoding:NSUTF8StringEncoding];
                
                event.title = text;
            } else if ([line hasPrefix:@"DTEND"]) {
                NSArray *dataArray = [line componentsSeparatedByString:SeparatedStr1];
                event.endDate = [NSDate dateWithTZString:dataArray[1] andTZID:timeCode andTZOffset:tzoffsetFrom];
            } else if ([line hasPrefix:@"DTSTART"]) {
                NSArray *dataArray = [line componentsSeparatedByString:SeparatedStr1];
                event.startDate = [NSDate dateWithTZString:dataArray[1] andTZID:timeCode andTZOffset:tzoffsetFrom];
            } else if ([line hasPrefix:@"URL"]) {
                NSArray *dataArray = [line componentsSeparatedByString:SeparatedStr1];
                event.URL = [NSURL URLWithString:dataArray[1]];
            } else if ([line hasPrefix:@"LCOATION"]) {
                NSArray *dataArray = [line componentsSeparatedByString:SeparatedStr1];
                event.location = dataArray[1];
            } else if ([line hasPrefix:@"DESCRIPTION"]) {
                NSArray *dataArray = [line componentsSeparatedByString:SeparatedStr1];
                // 解码
                NSString *text = [dataArray[1] stringByReplacingOccurrencesOfString:@"=" withString:@"%"];
                text = [NSString URLdecode:text stringEncoding:NSUTF8StringEncoding];
                
                event.notes = text;
            } else if ([line hasPrefix:@"X-ALLDAY"]) {
                NSArray *dataArray = [line componentsSeparatedByString:SeparatedStr1];
                event.allDay = [dataArray[1] isEqual:@"0"] ? false : true;
            } else if ([line hasPrefix:@"TRIGGER"]) {
                NSArray *dataArray = [line componentsSeparatedByString:SeparatedStr1];
                NSString *countMinutes = [NSString stringRangeOfStringWithStart:@"PT" andEnd:@"M" andDealStr:dataArray[1]];
                EKAlarm *alarm = [EKAlarm alarmWithRelativeOffset:[countMinutes integerValue] * -60];
                [event addAlarm:alarm];
            }
            
            // 退出位
            if ([line hasPrefix:@"END:VEVENT"]) {
                [event setCalendar:[store defaultCalendarForNewEvents]];
                isIn = false;
                index++;
            }
        }
    }

    return eventsArray;
}

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

iOS日历中的日程生成VCalendar 2.0(.vcs)格式的字符串和解析 的相关文章

  • BUG - 在 IOS 中没有选择标签的完成按钮

    我正在使用最新的离子并有一个简单的选择标签
  • 将 UITableViewDataSource 与具有子视图的自定义单元格结合使用

    在 UITableView 中使用自定义单元格时 我遇到了奇怪的表格重叠 Problem 向下滚动 最后两行上面画有顶部两行 向上滚动 前两行上面画有下面两行 这是 UITableViewDataSource 的代码 func tableV
  • 创建类似于邮件应用程序菜单的 iPhone 弹出菜单

    当您想要回复消息时 我想创建一个类似于邮件应用程序中的弹出菜单 我在多个应用程序中看到过这一点 所以我不确定框架中是否内置了某些内容或一些示例代码 在 Swift 中创建操作表 代码已使用 Swift 5 进行测试 从 iOS 8 开始 U
  • 部署目标是什么意思?

    这是我假设的一个非常简单的问题 有人可以告诉我部署目标是什么意思吗 如果我选择 iOS 10 是否意味着只有 iOS 10 的用户才能下载该应用程序 选择较低的部署目标是否不好 另外 继续部署目标 是否不建议在较低的部署目标上运行 假设您已
  • 如何在 iOS 中查找蓝牙音频设备

    好的 我正在开发一个有趣的项目 该项目有一个障碍 我需要为我的 iOS 应用程序启用蓝牙音频支持 我遇到的障碍是我什至无法开始获取已连接的蓝牙音频设备的列表 即使我的 iPhone 5S 可以识别我的耳机 大约 3 4 岁的耳机 LG HB
  • 如何在 iOS 上压缩 Realm DB?

    我想定期压缩 iOS 上的 Realm 实例以回收空间 我认为该过程是将数据库复制到临时位置 然后将其复制回来并使用新的default realm 文件 我的问题是Realm 其行为就像单例并回收对象 因此我无法真正关闭它并告诉它打开新的
  • 将第 3 方库 ZXing 导入 Xcode

    我尝试了多种方法将第 3 方库 ZXing 导入我的 iOS 应用程序 但所有方法都很痛苦 或者根本不起作用 如果有人可以建议我做错了什么 或者提出导入 ZXing 等库的更好方法 我将非常感激 一定比这个容易 这就是我所做的 结果是 My
  • iOS8 CoreData“使用未实现的初始化程序”

    我尝试运行我的应用程序时收到以下错误 致命错误 对类 rcresttest CatalogItem 使用未实现的初始化程序 init entity insertIntoManagedObjectContext 我可以通过将数据模型中的实体类
  • 如何在IOS中的UIStackView中设置权重

    UIStackView与安卓类似LinearLayout但我不知道如何设置子视图的权重 假设我有一个垂直的UIStackView and 3 UIImageView就在里面 我想连续设置权重3 6 1UIImageViews 我怎么做 UI
  • XMPPFramework - 如何创建多用户聊天室?

    我如何使用XMPPFramework在iPhone中实现GroupChat 我尝试了以下代码 但房间没有创建 我如何知道房间是否创建 XMPPRoomDelegate没有被调用 当Stream断开连接时 调用handleDidLeaveRo
  • 修补应用内购买黑客;卡在第四步

    正如我们许多人所知 苹果最近出现了一种情况 黑客可以免费获得任何应用内购买 苹果最近发布了这个文件 http developer apple com library ios releasenotes StoreKit IAP Receipt
  • 从 UIImagePickerController 相机视图推送 viewController

    我正在开发一款消息应用程序 类似于 WhatsApp 用户可以互相发送文本和图像消息 当用户想要发送图像时 他可以从相机胶卷中选择一张图像 也可以用相机拍摄一张图像 这就是我介绍的方式UIImagePickerController对于这两种
  • 如何打开定位服务

    当有人第一次拒绝时 如何从实际应用程序重新打开定位服务 我可以选择关闭或打开它 您只能提示他们在屏幕上打开定位服务 如下所示 UIApplication sharedApplication openURL NSURL URLWithStri
  • NSString – 静态还是内联?有性能提升吗?

    如果我写的话会有任何性能提升吗 NSString helloStringWithName NSString name static NSString formatString Hello return NSString stringWith
  • 带操作按钮的颤动本地通知

    我在我的 flutter 项目中尝试了 flutter 本地通知插件 它在简单通知上工作正常 但我需要带有操作按钮的通知功能 请帮助我或建议我实现此功能 不幸的是 flutter local notifications 插件尚不支持操作按钮
  • 当地图视图只是屏幕的一部分时,如何在 iOS 模拟器中进行捏合?

    我在 iPad 上有一个视图 我正在添加MKMapView也就是说 全屏高度的一半 然而 当我尝试在 iOS 模拟器上进行捏合时 它不起作用 因为 to nubs 填充了模拟器上的整个 iPad 视图 And so with the map
  • 如何使用AudioKit保存音频文件?

    我有音频文件 我给它做了一些效果 let pitchshifter AKPitchShifter self audioPlayer pitchshifter shift 10 AudioKit output pitchshifter 如果我
  • 在 iOS 中,如何创建一个始终位于所有其他视图控制器之上的按钮?

    无论是否呈现模态或用户执行任何类型的转场 有没有办法让按钮在整个应用程序中 始终位于顶部 而不是屏幕顶部 有什么方法可以让这个按钮可拖动并可捕捉到屏幕上吗 我正在以苹果自己的辅助触摸作为此类按钮的示例 您可以通过创建自己的子类来做到这一点U
  • 如何将 ios7 通用应用程序升级到基于 Xcode 6 的通用故事板应用程序?

    我目前有一个基于 xcode 5 ios 7 的通用应用程序 因此有两个故事板 我正在考虑将其更新到 ios 8 有没有办法 最佳方法将两个故事板迁移到通用的单个故事板 我在 xcode 6 中看不到转换选项 None
  • 在 UIScrollview 上显示缩略图的最佳方法是什么(从服务器下载)

    我想在 UIScrollview 如照片应用程序 上显示许多图像 作为缩略图 所有图像将从服务器下载 据我所知 有几种选择 1 通过创建 UIImageviews 然后将它们添加为主滚动视图上的子视图 2 通过子类化一个UIView类 然后

随机推荐