I have a model translator. It reads AModel's properties, and copy the value to BModel's same property if BModel has. Now I have a crash report shows the property is null. That is so strange. The property is got from a property list and it is null.
Here is the message:
*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<XXXXXX 0x1594051a0> valueForUndefinedKey:]: this class is not key value coding-compliant for the key (null).
+ (instancetype)convertSourceObject:(id)sourceObject {
if (!sourceObject) {
return nil;
}
id destination_object = [[self alloc] init];
uint destination_properties_count = 0;
objc_property_t *destination_properties = class_copyPropertyList([self class], &destination_properties_count);
for (int i = 0; i < destination_properties_count; i++) {
objc_property_t destination_property = destination_properties[i];
uint source_attributes_count = 0, destination_attributes_count = 0;
objc_property_attribute_t *destination_attributes = property_copyAttributeList(destination_property, &destination_attributes_count);
const char *property_char_name = property_getName(destination_property);
NSString *property_name = [NSString stringWithUTF8String:property_char_name];
objc_property_t source_property = class_getProperty([sourceObject class], property_char_name);
if (source_property && ![ignorePropertyNames() containsObject:property_name]) {
objc_property_attribute_t *source_attributes = property_copyAttributeList(source_property, &source_attributes_count);
NSString *source_ivar_type = #"";
NSString *destination_ivar_type = #"";
for (int i = 0; i < source_attributes_count; i++) {
if (strcmp(source_attributes[i].name, "T") == 0) {
source_ivar_type = [[NSString stringWithUTF8String:source_attributes[i].value] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#"#\""]];
break;
}
}
for (int i = 0; i < destination_attributes_count; i++) {
if (strcmp(destination_attributes[i].name, "T") == 0) {
destination_ivar_type = [[NSString stringWithUTF8String:destination_attributes[i].value] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#"#\""]];
break;
}
}
if ([self isPropertySetType:source_ivar_type]) {
id source_value = [sourceObject valueForKey:property_name];
if ([source_value isKindOfClass:[NSArray class]]) {
NSArray *destination_array = [self arrayConvert:(NSArray*)source_value];
if (destination_array) {
[destination_object setValue:destination_array forKey:property_name];
}
} else if ([source_value isKindOfClass:[NSDictionary class]]) {
NSDictionary *destination_dict = [self dictionaryConvert:(NSDictionary *)source_value];
if (destination_dict) {
[destination_object setValue:destination_dict forKey:property_name];
}
}
} else {
if ([destination_ivar_type isEqualToString:source_ivar_type]) {
id source_value = [sourceObject valueForKey:property_name];
if (source_value) {
[destination_object setValue:source_value forKey:property_name];
}
} else {
id source_value = [sourceObject valueForKey:property_name];
id destination_value = [NSClassFromString(destination_ivar_type) convertSourceObject:source_value];
if (destination_value) {
[destination_object setValue:destination_value forKey:property_name];
}
}
}
free(source_attributes);
} else {
continue;
}
free(destination_attributes);
}
free(destination_properties);
return destination_object;
}
The error means: you try to read a property which name's "null" AModel's property , but it doesn't exit in AModel.
You should overwrite valueForUndefinedKey in your Model Class, debug the UndefinedKey.
Check your code.It seems happened at
id source_value = [sourceObject valueForKey:property_name];
NSLog debug the property_name, see what you got.
Related
I have seen many of the answers but didn't get my answer. So that's why I decide to post a question. If anybody can find the helpful link or answer will be helpful.
Here is my array of dictionary:
<__NSArrayM 0x283ba04e0>(
{
failvalues = (
"Check 1"
);
fieldname = "Check 3";
fieldvalue = (
"Check 1",
"Check 2"
);
showtype = mandatory;
tagvalue = 0;
},
{
failvalues = (
Fail
);
fieldname = "Dropdown 3";
fieldvalue = (
Fail
);
showtype = mandatory;
tagvalue = 1;
},
{
failvalues = (
"Check 1",
"Check 4"
);
fieldname = "Check 4";
fieldvalue = (
"Check 1",
"Check 2"
);
showtype = mandatory;
tagvalue = 2;
})
So I want to check if the fieldvalue contains failvalues or not.
Below is the code which I have tried but it doesn't seem to work:
for (int i = 0; i< [arrFields count]; i++) {
if ([[[arrFields objectAtIndex:i]objectForKey:#"failvalues"] isKindOfClass:[NSArray class]]) {
if (![[[[arrFields objectAtIndex:i] objectForKey:#"failvalues"] objectAtIndex:0] isEqualToString:#""]) {
NSLog(#"Field Values %#",[[arrFields objectAtIndex:i]objectForKey:#"fieldvalue"]);
NSArray *failValues = [[arrFields objectAtIndex:i] objectForKey:#"failvalues"];
for (int j = 0; j < [failValues count]; j++) {
if ([failValues containsObject:[[arrFields objectAtIndex:i]objectForKey:#"fieldvalue"]]) {
NSLog(#"Contains %#",[[arrFields objectAtIndex:i]objectForKey:#"fieldvalue"]);
} else {
NSLog(#"No fail values");
}
}
} else {
NSLog(#"No Fail Fields");
}
} else {
NSLog(#"Not an array");
}
}
EDIT:
This one I have tried but how to break both the loops
for (int i = 0; i< [arrFields count]; i++) {
NSArray *fieldValues = [[arrFields objectAtIndex:i]objectForKey:#"fieldvalue"];
NSArray *failValues = [[arrFields objectAtIndex:i] objectForKey:#"failvalues"];
if (![[[[arrFields objectAtIndex:i] objectForKey:#"failvalues"] objectAtIndex:0] isEqualToString:#""]) {
//NSLog(#"Field Values %#",[[arrFields objectAtIndex:i]objectForKey:#"fieldvalue"]);
for(NSString *value in fieldValues){
if ([failValues containsObject:value]) {
NSLog(#"Contains %#",value);
scanStatus = TRUE;
return;
}
}
} else {
NSLog(#"No Fail Fields");
}
}
Thanks in advance!
This is a classic use case for the feared and dreaded goto. It's well known that goto can create disastrously messy code, but in cases like this it'll make things cleaner. You have to know when to use goto, and definitely use it sparingly. But here's how I'd write your code:
BOOL found = NO;
for (NSDictionary *dict in arrFields)
{
NSArray *fieldValues = dict[#"fieldvalue"];
NSArray *failValues = dict[#"failvalues"];
if (![failValues[0] isEqualToString:#""]) {
for (NSString *value in fieldValue) {
if ([failValues containsObject:value]) {
NSLog(#"Contains %#",value);
found = YES;
goto leaveLoops;
}
}
}
}
leaveLoops:
if (found) NSLog(#"Found one.");
else NSLog(#"Didn't find one.");
And if you cannot bring yourself to use goto (you wouldn't be alone,) here's a gotoless alternative:
BOOL found = NO;
for (NSDictionary *dict in arrFields)
{
NSArray *fieldValues = dict[#"fieldvalue"];
NSArray *failValues = dict[#"failvalues"];
if (![failValues[0] isEqualToString:#""]) {
for (NSString *value in fieldValue) {
if ([failValues containsObject:value]) {
NSLog(#"Contains %#",value);
found = YES;
break;
}
}
if (found) break;
}
}
if (found) NSLog(#"Found one.");
else NSLog(#"Didn't find one.");
I have an array of dictionary like below
self->arrField: (
{
fieldname = "Have you ever had any one of the following:";
fieldvalue = (
Diabetes,
Hypertension
);
tagvalue = 0;
},
{
fieldname = "By continuing with this survey, you agree to our terms of use and Parsons Information Governance and Privacy Policies, Procedures and Standards, available on the Corporate Policy Center.";
fieldvalue = Agree;
tagvalue = 1;
},
{
fieldname = "Have you tested positive for COVID-19 in the last 10 days?";
fieldvalue = No;
tagvalue = 4;
},
{
fieldname = "Do you have any known heart conditions or on any medications that elevate your heart rate";
fieldvalue = Yes;
tagvalue = 6;
},
{
fieldname = "Have you received a COVID-19 test in the past 48 hours";
fieldvalue = Yes;
tagvalue = 7;
},
{
fieldname = "In the last 48 hours have you experienced any of these symptoms";
fieldvalue = (
cough,
fever
);
tagvalue = 10;
}
)
So if the user changes any of the fieldvalue I need to replace that array, I have tried using replaceObjectAtIndex but it will not work out because I need compare the string.
Below is my implementation:
-(void)ChkUnChk:(UIButton*)sender {
dispatch_async(dispatch_get_main_queue(), ^{
UIButton *btn=(UIButton *)sender;
NSString *strValue = btn.accessibilityHint;
NSString *Str=[NSString stringWithFormat:#"%d",(int)btn.tag];
int iTag = [[sender.layer valueForKey:#"anyKey"] intValue];
// new Implementation
NSMutableDictionary *dictFields = [[NSMutableDictionary alloc] init];
NSMutableArray *arrFieldvalue = [[NSMutableArray alloc] init];
[dictFields setObject:[[self->dictCustomFieldGroups valueForKey:#"name"] objectAtIndex:iTag] forKey:#"fieldname"];
[dictFields setObject:[NSString stringWithFormat:#"%ld",(long)iTag] forKey:#"tagvalue"];
if ([self isTagIDAvailable:iTag]) {
arrFieldvalue = [[[self->arrTempCheckboxFields objectAtIndex:self->checkboxIndex] valueForKey:#"fieldvalue"] mutableCopy];
BOOL isTheObjectThere = [arrFieldvalue containsObject: strValue];
if (isTheObjectThere) {
NSLog(#"string contains");
[btn setBackgroundImage:[UIImage systemImageNamed:#"square"] forState:UIControlStateNormal];
for(id item in arrFieldvalue) {
if([item isEqual:strValue]) {
[arrFieldvalue removeObject:item];
[dictFields setObject:arrFieldvalue forKey:#"fieldvalue"];
break;
}
}
} else {
NSLog(#"string does not contain!");
[btn setBackgroundImage:[UIImage systemImageNamed:#"checkmark.square"] forState:UIControlStateNormal];
[arrFieldvalue addObject:strValue];
[dictFields setObject:arrFieldvalue forKey:#"fieldvalue"];
}
NSInteger count = [self->arrFields count];
for (NSInteger index = (count - 1); index >= 0; index--) {
NSArray *p = self->arrFields[index];
if ([[self->arrFields valueForKey:#"tagvalue"] isEqual:[NSNumber numberWithInt:iTag]]) {
[self->arrFields removeObjectAtIndex:index];
}
}
[self->arrFields replaceObjectAtIndex:iTag withObject:dictFields];
[self->arrTempCheckboxFields replaceObjectAtIndex:self->checkboxIndex withObject:dictFields];
} else {
[btn setBackgroundImage:[UIImage systemImageNamed:#"checkmark.square"] forState:UIControlStateNormal];
[arrFieldvalue addObject:strValue];
[dictFields setObject:arrFieldvalue forKey:#"fieldvalue"];
[self->arrFields addObject:dictFields];
[self->arrTempCheckboxFields addObject:dictFields];
}
NSLog(#"self->arrField: %#",self->arrFields);
});
}
-(BOOL) isTagIDAvailable:(int)tagID {
BOOL retVal = FALSE;
BOOL tagIdFound = FALSE;
if ([arrTagID count] > 0) {
for (int i = 0; i < [arrTagID count]; i++) {
if ([[NSNumber numberWithInteger:tagID] isEqualToNumber:[arrTagID objectAtIndex:i]]) {
tagIdFound = TRUE;
checkboxIndex = i;
retVal = TRUE;
break;
}
}
if (!tagIdFound) {
[arrTagID addObject:[NSNumber numberWithInteger:tagID]];
checkboxIndex = (int)[arrTagID count];
retVal = FALSE;
}
} else {
[arrTagID addObject:[NSNumber numberWithInteger:tagID]];
retVal = FALSE;
}
return retVal;
}
I have done something from line no 32, like I will remove that array value and add it again.But I am not sure how to do that. If more detail require I can provide.
Thanks in Advance.
I'm setting up
appDele.mMediaManager=[[BluzManager alloc] initWithConnector:appDele.mBluzConnector];
and Third-party library methods are also implemented. When I init object then the problem goes:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayM totalLength]: unrecognized
Is the NSArray about _m_arrBT goes wrong?
-(void)connectedPeripheral:(CBPeripheral *)peripheral{
if (m_dictConnect != nil) {
BOOL found = NO;
for (int i = 0; i < _m_arrBT.count; i++) {
NSMutableDictionary *dict = [_m_arrBT objectAtIndex:i];
CBPeripheral *device = [dict objectForKey:#"peripheral"];
CBPeripheral *connected = [m_dictConnect objectForKey:#"peripheral"];
// if (device.UUID == connected.UUID) {
if ([self isPeripheral:device equalPeripheral:connected]) {
found = YES;
break;
}
}
if (!found) {
[_m_arrBT addObject:m_dictConnect];
}
_m_arrBT = [self sortDeviceArray:_m_arrBT];
} else {
for (NSDictionary *dict in _m_arrBT) {
CBPeripheral *device = [dict objectForKey:#"peripheral"];
// if (device.UUID == peripheral.UUID) {
if ([self isPeripheral:device equalPeripheral:peripheral]) {
NSLog(#"devicename=%#",[dict objectForKey:#"name"]);
}
}
}
appDele.mMediaManager=[[BluzManager alloc] initWithConnector:appDele.mBluzConnector];
appDele.globalManager=[appDele.mMediaManager getGlobalManager:self];
mUserDiconnected = NO;
m_bConnect=YES;
_m_arrBT = [self sortDeviceArray:_m_arrBT];
[self.tableView reloadData];
if (!mManagerReady || !mHotplugCardArrived || !mHotplugUhostArrived || !mHotplugUSBArrived) {
// [self managerReady];
}
}
Here's the source code for the method that appears to be causing the leak.
- (void)search:(CDVInvokedUrlCommand*)command
{
NSString* callbackId = command.callbackId;
NSArray* fields = [command argumentAtIndex:0];
NSDictionary* findOptions = [command argumentAtIndex:1 withDefault:[NSNull null]];
[self.commandDelegate runInBackground:^{
// from Apple: Important You must ensure that an instance of ABAddressBookRef is used by only one thread.
// which is why address book is created within the dispatch queue.
// more details here: http: //blog.byadrian.net/2012/05/05/ios-addressbook-framework-and-gcd/
CDVAddressBookHelper* abHelper = [[CDVAddressBookHelper alloc] init];
CDVContacts* __weak weakSelf = self; // play it safe to avoid retain cycles
// it gets uglier, block within block.....
[abHelper createAddressBook: ^(ABAddressBookRef addrBook, CDVAddressBookAccessError* errCode) {
if (addrBook == NULL) {
// permission was denied or other error - return error
CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:errCode ? (int)errCode.errorCode:UNKNOWN_ERROR];
[weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId];
return;
}
NSArray* foundRecords = nil;
// get the findOptions values
BOOL multiple = NO; // default is false
NSString* filter = nil;
NSArray* desiredFields = nil;
if (![findOptions isKindOfClass:[NSNull class]]) {
id value = nil;
filter = (NSString*)[findOptions objectForKey:#"filter"];
value = [findOptions objectForKey:#"multiple"];
if ([value isKindOfClass:[NSNumber class]]) {
// multiple is a boolean that will come through as an NSNumber
multiple = [(NSNumber*)value boolValue];
// NSLog(#"multiple is: %d", multiple);
}
desiredFields = [findOptions objectForKey:#"desiredFields"];
// return all fields if desired fields are not explicitly defined
if (desiredFields == nil || desiredFields.count == 0) {
desiredFields = [NSArray arrayWithObjects:#"*", nil];
}
}
NSDictionary* searchFields = [[CDVContact class] calcReturnFields:fields];
NSDictionary* returnFields = [[CDVContact class] calcReturnFields:desiredFields];
NSMutableArray* matches = nil;
if (!filter || [filter isEqualToString:#""]) {
// get all records
foundRecords = (__bridge_transfer NSArray*)ABAddressBookCopyArrayOfAllPeople(addrBook);
if (foundRecords && ([foundRecords count] > 0)) {
// create Contacts and put into matches array
// doesn't make sense to ask for all records when multiple == NO but better check
int xferCount = multiple == YES ? (int)[foundRecords count] : 1;
matches = [NSMutableArray arrayWithCapacity:xferCount];
for (int k = 0; k < xferCount; k++) {
CDVContact* xferContact = [[CDVContact alloc] initFromABRecord:(__bridge ABRecordRef)[foundRecords objectAtIndex:k]];
[matches addObject:xferContact];
xferContact = nil;
}
}
} else {
foundRecords = (__bridge_transfer NSArray*)ABAddressBookCopyArrayOfAllPeople(addrBook);
matches = [NSMutableArray arrayWithCapacity:1];
BOOL bFound = NO;
int testCount = (int)[foundRecords count];
for (int j = 0; j < testCount; j++) {
CDVContact* testContact = [[CDVContact alloc] initFromABRecord:(__bridge ABRecordRef)[foundRecords objectAtIndex:j]];
if (testContact) {
bFound = [testContact foundValue:filter inFields:searchFields];
if (bFound) {
[matches addObject:testContact];
}
testContact = nil;
}
}
}
NSMutableArray* returnContacts = [NSMutableArray arrayWithCapacity:1];
if ((matches != nil) && ([matches count] > 0)) {
// convert to JS Contacts format and return in callback
// - returnFields determines what properties to return
#autoreleasepool {
int count = multiple == YES ? (int)[matches count] : 1;
for (int i = 0; i < count; i++) {
CDVContact* newContact = [matches objectAtIndex:i];
NSDictionary* aContact = [newContact toDictionary:returnFields];
[returnContacts addObject:aContact];
}
}
}
// return found contacts (array is empty if no contacts found)
CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:returnContacts];
[weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId];
// NSLog(#"findCallback string: %#", jsString);
if (addrBook) {
CFRelease(addrBook);
}
}];
}]; // end of workQueue block
return;
}
The specific line that is doing most of the leaking is foundRecords = (__bridge_transfer NSArray*)ABAddressBookCopyArrayOfAllPeople(addrBook);, but this is confusing, given that the correct __bridge_transfer call is used. What's going on here?
I have a large NSDictionary. Fx.
"m:GetFolderResponse" = {
"m:ResponseMessages" = {
"m:GetFolderResponseMessage" = {
ResponseClass = Success;
"m:Folders" = {
"t:CalendarFolder" = {
"t:ChildFolderCount" = {
text = 0;
};
"t:DisplayName" = {
text = Calendar;
};
"t:FolderId" = {
ChangeKey = "AgAAABYAAABGewbOYWpKSrW/k23iIoFkAPJWd7/8";
Id = "AAMkADkwOWE2NjEyLTMwZWQtNGYyMy05OGQ1LWZjZjFkZGY5MTBhMAAuAAAAAAC1cjo8jkv5SKjQt5WaSmd1AQBGewbOYWpKSrW/k23iIoFkAPJWc0NrAAA=";
};
};
};
"m:ResponseCode" = {
text = NoError;
};
};
};
"xmlns:m" = "http://schemas.microsoft.com/exchange/services/2006/messages";
"xmlns:t" = "http://schemas.microsoft.com/exchange/services/2006/types";
};
}
As you might have guessed, there can be multiple in the m:Folders. Therefore I would like to find m:Folders child, where t:DisplayName is equal to a variable value. How can I do this?
- (void)filterMutableDictionary:(NSDictionary*)aDictionary andKeyName:(NSString *)keyName
{
if ([keyName isEqualToString:#"t:CalendarFolder"]) {
if ([[[aDictionary objectForKey:#"t:DisplayName"] objectForKey:#"text"] isEqualToString:searchCalendarName]) {
NSDictionary *temp = [aDictionary objectForKey:#"t:FolderId"];
CalID = [temp objectForKey:#"Id"];
CalChangeID = [temp objectForKey:#"ChangeKey"];
}
}
// enumerate key/values, filtering appropriately, recursing as necessary
NSLog(#"%#",aDictionary);
[aDictionary enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) {
if ([value isKindOfClass: [NSMutableDictionary class]] || [value isKindOfClass: [NSDictionary class]]) {
[self filterMutableDictionary: value andKeyName:key];
}
}];
}