[英]Mirror of EKEvent does not show the data
For my EVReflection library I came to a case where a Mirror for an EKEvent did not return any information. 对于我的EVReflection库,我遇到了EKEvent的镜像未返回任何信息的情况。 Even when going to the complete basics a Mirror did not return anything. 即使使用完整的基础知识,Mirror也不会返回任何内容。 When you set a breakpoint after the Mirror line, you will see that there is nothing in the Mirror object. 在Mirror行之后设置断点时,您将看到Mirror对象中没有任何内容。 Is this a bug or am I missing something? 这是错误还是我错过了什么?
update: I extended the demo for getting the properties using the old Objective C objc_property_t and property_getName functions. 更新:我扩展了使用旧的Objective C objc_property_t和property_getName函数获取属性的演示。 It will return a list of properties. 它将返回属性列表。 But then it will crash when you get the .value(forKey: 但是,当您获得.value(forKey:
#if os(tvOS)
// Eventkit is not supported on tvOS
#else
import XCTest
import Foundation
import EventKit
let store = EKEventStore()
class EVReflectionEventKitTests: XCTestCase {
func testEventKit() {
let exp = expectation(description: "eventStore")
store.requestAccess(to: .event, completion: { (granted, error) in
let event = EKEvent(eventStore: store)
event.startDate = Date().addingTimeInterval(10000)
event.title = "title"
event.location = "here"
event.endDate = Date().addingTimeInterval(20000)
event.notes = "notes"
event.calendar = store.defaultCalendarForNewEvents
event.addAlarm(EKAlarm(absoluteDate: Date().addingTimeInterval(10000)))
//WARNING: You will get events in your agenda! Disable next line if you don't want that
//try? store.save(event, span: EKSpan.thisEvent, commit: true)
let m = Mirror(reflecting: event)
print("mirror children = \(m.children.count)")
let oc = self.properties(event)
print(oc)
for p in oc {
var value: Any? = nil
value = event.value(forKey: p)
print("\(p) = \(String(describing: value))")
}
exp.fulfill()
})
waitForExpectations(timeout: 10) { error in
XCTAssertNil(error, "\(error?.localizedDescription ?? "")")
}
}
func properties(_ classToInspect: NSObject) -> [String] {
var count = UInt32()
let classToInspect = NSURL.self
let properties = class_copyPropertyList(classToInspect, &count)
var propertyNames = [String]()
let intCount = Int(count)
for i in 0 ..< intCount {
let property : objc_property_t = properties![i]!
guard let propertyName = NSString(utf8String: property_getName(property)) as String? else {
debugPrint("Couldn't unwrap property name for \(property)")
break
}
propertyNames.append(propertyName)
}
free(properties)
return propertyNames
}
}
#endif
This appears to be intended behavior: 这似乎是预期的行为:
_ObjCMirror
child count implementation just defers to the _getObjCCount
shim, whose actual function name is specified as swift_ObjCMirror_count
. _ObjCMirror
子计数实现仅针对_getObjCCount
填充程序,其实际函数名称指定为swift_ObjCMirror_count
。 swift_ObjCMirror_count
is rigged up to just return 0
all the time when REFLECT_OBJC_IVARS
is defined to a falsey value. swift_ObjCMirror_count
是七拼八凑刚刚返回0
时,所有的时间REFLECT_OBJC_IVARS
被定义为一个falsey值。 REFLECT_OBJC_IVARS
is in the Swift source? 猜猜Swift源中REFLECT_OBJC_IVARS
的值是多少? That's right, it's set to 0
. 没错,它设置为0
。 If it were non-zero, it'd be dumping ivars, not properties. 如果它不为零,则将转储ivars,而不是属性。 A property's getter attribute can make it so there's no method matching the property name, and its backing ivar can also be named differently from the property, if there even is one: both of these could cause -valueForKey:
to fail out. 属性的getter属性可以使属性匹配,因此没有方法可以匹配属性名称,并且即使存在属性,其后缀ivar也可以与属性不同地命名:两者都可能导致-valueForKey:
失败。 Most classes don't disable direct ivar access via key-value coding, so you might want to try dumping the ivars instead and accessing those. 大多数类都不会通过键值编码禁用直接ivar访问,因此您可能想尝试转储ivars并访问它们。
You might also want to note that some classes lie about their layout, like NSURL
, which was explicitly blacklisted from reflection even when reflection is enabled for Obj-C classes! 您可能还需要注意,有些类位于它们的布局上,例如NSURL
,即使为Obj-C类启用了反射 , NSURL
也已从反射中明确列入黑名单 !
ETA: Here's an example of dumping the ivars. 预计到达时间:这是一个丢弃ivars的示例。 It's not terribly useful in this case, unfortunately. 不幸的是,在这种情况下它并不是非常有用。
The code to generate a dictionary based on the ivars: 基于ivars生成字典的代码:
func makeDictionary(describing object: AnyObject) -> Dictionary<String, Any> {
var dict = [String: Any]()
guard let cls = object_getClass(object) else {
print("object has no class:", object)
return dict
}
var ivarCount: UInt32 = 0
guard let ivarsPtr: UnsafeMutablePointer<Ivar?> = class_copyIvarList(cls, &ivarCount), ivarCount > 0
else {
print("object has no ivars, or failed to get any:", object)
return dict
}
let ivars = UnsafeBufferPointer(start: ivarsPtr, count: numericCast(ivarCount))
for ivar in ivars {
guard let int8Ptr = ivar_getName(ivar) else {
print("failed to get name for ivar:", ivar as Any)
continue
}
let name = String(cString: int8Ptr)
let value = object_getIvar(object, ivar)
print("value for \(name):", value as Any)
dict[name] = value ?? object.value(forKey: name) ?? NSNull()
}
return dict
}
And the output for an event created as described in your question (manually hard-wrapped for ease of review): 以及根据您的问题所述创建的事件的输出(为便于查看,进行了手动包装):
dictionary version based on direct ivar access:
["isYearlessLeapMonthBirthday": 0
, "_birthdayPersonID": 0
, "_sliceDate": <null>
, "nameForBirthday": <null>
, "_futureLocalUidForSliceChild": <null>
, "isYearlessBirthday": 0
, "_cachedDuration": <null>
, "_cachedStartOfDayForStartDate": <null>
, "_isPhantom": 0
, "lunarCalendarString": <null>
, "_cachedIsMultiDayTimedEvent": <null>
, "_cachedTimeValuesCalendar": <null>
, "birthdayTitle": <null>
, "_cachedStartOfDayForEndDate": <null>
, "_cachedDaysSpanned": <null>
, "_cachedJunkStatus": 0
, "sliceParentID": <null>
, "participantsStatus": 0
]
import Foundation
import EventKit
import EVReflection
class serializedEvent: EVObject {
var myEvent: EKEvent = EKEvent(eventStore: globalStore)
//globalstore is an EKEventstore global object
then in one of my controllers i do (i just have a full event named: event created with alarms of type EKalarms and recurrency Rule of EKRecurrencyRule type): 然后在我的一个控制器中做(我只有一个完整的事件,名为:用EKalarms类型的警报和EKRecurrencyRule类型的重复规则创建的事件):
print("event before serialization :")
print(event)
let serEvent: serializedEvent = serializedEvent()
serEvent.myEvent=event
let jsonEvent = serEvent.toJsonString()
let newEvent = serializedEvent(json: jsonEvent).myEvent
print("newEvent: =")
print(newEvent)
This is a real example output : 这是一个真实的示例输出:
event before serialization :
EKEvent <0x174130040>
{
EKEvent <0x174130040>
{ title = Matrimonio;
location = ;
calendar = EKCalendar <0x1740b4d60> {title = Calendario; type = CalDAV; allowsModify = YES; color = #029ae4;};
alarms = (
"EKAlarm <0x1740d9d00> {triggerInterval = -54000.000000}",
"EKAlarm <0x1740d8950> {triggerInterval = 0.000000}"
);
URL = (null);
lastModified = 2016-06-06 15:15:17 +0000;
startTimeZone = (null);
startTimeZone = (null)
};
location = ;
structuredLocation = (null);
startDate = 2009-06-06 22:00:00 +0000;
endDate = 2009-06-07 21:59:59 +0000;
allDay = 1;
floating = 1;
recurrence = EKRecurrenceRule <0x1702b2c00> RRULE FREQ=YEARLY;INTERVAL=1;BYMONTH=6;BYMONTHDAY=7;
attendees = (null);
travelTime = (null);
startLocation = (null);
};
2017-04-28 21:23:25.226855 InstaEvent Share[19166:5967595] ERROR:
Unexpected type while converting value for JsonSerialization:
EKEvent <0x174130040>
{
EKEvent <0x174130040>
{ title = Matrimonio;
location = ;
calendar = EKCalendar <0x1740b4d60> {title = Calendario; type
= CalDAV; allowsModify = YES; color = #029ae4;};
alarms = (
"EKAlarm <0x1740d9d00> {triggerInterval = -54000.000000}",
"EKAlarm <0x1740d8950> {triggerInterval = 0.000000}"
);
URL = (null);
lastModified = 2016-06-06 15:15:17 +0000;
startTimeZone = (null);
startTimeZone = (null)
};
location = ;
structuredLocation = (null);
startDate = 2009-06-06 22:00:00 +0000;
endDate = 2009-06-07 21:59:59 +0000;
allDay = 1;
floating = 1;
recurrence = EKRecurrenceRule <0x1702b2c00> RRULE
FREQ=YEARLY;INTERVAL=1;BYMONTH=6;BYMONTHDAY=7;
attendees = (null);
travelTime = (null);
startLocation = (null);
};
newEvent: =
EKEvent <0x174130040>
{
EKEvent <0x174130040>
{ title = Matrimonio;
location = ;
calendar = EKCalendar <0x1740b4d60> {title = Calendario; type
= CalDAV; allowsModify = YES; color = #029ae4;};
alarms = (
"EKAlarm <0x1740d9d00> {triggerInterval = -54000.000000}",
"EKAlarm <0x1740d8950> {triggerInterval = 0.000000}"
);
URL = (null);
lastModified = 2016-06-06 15:15:17 +0000;
startTimeZone = (null);
startTimeZone = (null)
};
location = ;
structuredLocation = (null);
startDate = 2009-06-06 22:00:00 +0000;
endDate = 2009-06-07 21:59:59 +0000;
allDay = 1;
floating = 1;
recurrence = EKRecurrenceRule <0x1702b2c00> RRULE
FREQ=YEARLY;INTERVAL=1;BYMONTH=6;BYMONTHDAY=7;
attendees = (null);
travelTime = (null);
startLocation = (null);
};
but when we ask if it has alarms (and it should have, looking at output) 但是当我们问它是否有警报(它应该有警报,查看输出)时
print(newEvent.hasAlarms)
it fails with 它失败了
19170:5969208] -[__NSCFString hasAlarms]: unrecognized selector sent to instance 0x17425d340
This is tricky :( 这很棘手:(
EDIT : if in the SERIALIZER.SWITF class i add : extension EKEvent: EVReflectable { } then the newEvent is empty. 编辑:如果在SERIALIZER.SWITF类中添加:扩展名EKEvent:EVReflectable {},则newEvent为空。
..really tricky :D ..真的很棘手:D
Victor 胜利者
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.