Restkit: methodSignatureForSelector crashing in RKMappingOperation with EXC_BAD_ACCESS - restkit-0.20

In the file RKMappingOperation there is method
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector
{
return [self.object methodSignatureForSelector:selector];
}
which triggers exception on iPhone5 but the application continues to run. But on iPhone4S the application crashes with EXC_BAD_ACCESS.
I assume the exception is handled as stated in the documentation:
Raises NSInvalidArgumentException. Override this method in your concrete subclass to return a proper NSMethodSignature object for the given selector and the class your proxy objects stand in for.
The log file:
T restkit.object_mapping:RKMappingOperation.m:862 Performing mapping operation: <RKMappingOperation 0x181e1960> for 'TSNDecimal' object. Mapping values from object 10 to object <TSNDecimal: 0x18004bc0> (entity: TSNDecimal; id: 0x1819dcb0 <x-coredata:///TSNDecimal/t507A4693-CB2E-4194-966A-00BA8AD5CC70391> ;
data: {
number = 0;
responseName = nil;
sortId = 0;
ticket = nil;
}) with object mapping (null)
2014-07-07 13:17:50.194 VZN Mobile[440:8f0f] D restkit.object_mapping:RKPropertyInspector.m:131 Cached property inspection for Class 'TSNDecimal': {
number = {
isPrimitive = 0;
keyValueCodingClass = NSDecimalNumber;
name = number;
};
responseName = {
isPrimitive = 0;
keyValueCodingClass = NSString;
name = responseName;
};
sortId = {
isPrimitive = 0;
keyValueCodingClass = NSNumber;
name = sortId;
};
sortIdValue = {
isPrimitive = 1;
keyValueCodingClass = NSNumber;
name = sortIdValue;
};
ticket = {
isPrimitive = 0;
keyValueCodingClass = TSNTicketApiTO;
name = ticket;
};
}
2014-07-07 13:17:50.194 VZN Mobile[440:9f07] T restkit.object_mapping:RKMappingOperation.m:440 Found transformable value at keyPath '(null)'. Transforming from class '__NSCFNumber' to 'NSDecimalNumber'
2014-07-07 13:17:50.204 VZN Mobile[440:9f07] self.object:10

Thank you Wain for the comment. Actually it was caused by a wrong code in Restkit transforming NSDecimalNumber to NSNumber. There is a method in RKValueTransformers.m:
+ (instancetype)decimalNumberToNumberValueTransformer
{
....
....
RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, (#[ [NSNumber class], [NSDecimalNumber class]]), error);
if ([inputValue isKindOfClass:[NSNumber class]]) {
*outputValue = [NSDecimalNumber decimalNumberWithDecimal:[inputValue decimalValue]];
} else if ([inputValue isKindOfClass:[NSDecimalNumber class]]) {
*outputValue = inputValue;
}
return YES;
}];
}
The conditions have to be swapped this way:
if ([inputValue isKindOfClass:[NSDecimalNumber class]]) {
*outputValue = [NSDecimalNumber decimalNumberWithDecimal:[inputValue decimalValue]];
} else if ([inputValue isKindOfClass:[NSNumber class]]) {
*outputValue = inputValue;
}
Then the code is not crashing and it is working as author originally assumed.

Related

Convert subscript function from Objective C to Swift

I am trying to convert some Objective C code to Swift and can't manage to do it right with subscripting.
This is the method I am trying to migrate to Swift:
- (NSArray *)rangesOfSubstringAlphaNumeric:(NSString *)substring rangesLimit:(NSUInteger)rangesLimit {
NSAssert(rangesLimit, #"A range limit grather than 0 must be specified");
if (!substring.length) {
return nil;
}
static NSCharacterSet * restrictedCharacters = nil;
if (!restrictedCharacters) {
restrictedCharacters = [[NSCharacterSet alphanumericCharacterSet] invertedSet];
}
NSArray * substrings = [substring componentsSeparatedByCharactersInSet:restrictedCharacters];
NSMutableArray * allRanges = [NSMutableArray array];
NSString *searchedString = self;
for (NSString *stringToMatch in substrings) {
if (![stringToMatch isEqualToString:#""]) {
NSRange aRange;
NSUInteger lastLocation = 0;
NSUInteger foundRanges = 0;
while (foundRanges++ < rangesLimit &&
(aRange = [searchedString localizedStandardRangeOfString:stringToMatch]).location != NSNotFound) {
searchedString = [searchedString substringFromIndex:aRange.location + aRange.length];
aRange.location = aRange.location + lastLocation;
lastLocation = aRange.location + aRange.length;
[allRanges addObject:[NSValue valueWithRange:aRange]];
}
}
}
return allRanges.count ? [allRanges copy] : nil;
}
I got stuck on the subscripting part since it seems I cannot assign integer values to Indexes and conversion from Index to Int is out of hand for me I'm kind of stuck, this is what I managed to do:
func rangesOfAlphanumeric(substring: String, limit: UInt) -> [Range<String.Index>] {
guard limit > 0, !substring.isEmpty else {
if limit == 0 {
assert(false, "limit must be greather than 0")
}
return []
}
var searchedString = self
let substrings = substring.components(separatedBy: NSCharacterSet.restricted)
for stringToMatch in substrings {
if !stringToMatch.isEmpty {
// var aRange: Range<String.Index>?
// var lastLocation: UInt = 0
// var foundRanges: UInt = 0
// while foundRanges < limit,
// let tempRange = searchedString.localizedStandardRange(of: stringToMatch),
// !tempRange.isEmpty {
//
// searchedString = String(searchedString[tempRange.upperBound...])
// if let lastLocation = lastLocation {
// aRange = temp
// }
// }
}
}
}
UPDATE: Solution below.
Managed to resolve the issue using the ranges function posted here:
func rangesOfAlphanumeric(substring: String) -> [Range<String.Index>] {
var searchedString = self
let substrings = substring.components(separatedBy: NSCharacterSet.restricted)
return substrings.compactMap { (stringToMatch) -> [Range<String.Index>]? in
guard !stringToMatch.isEmpty else {
return nil
}
let ranges = searchedString.ranges(of: stringToMatch, options: [
.diacriticInsensitive,
.caseInsensitive
])
if let lastRange = ranges.last {
searchedString = String(searchedString[index(after: lastRange.upperBound)])
}
return ranges
}.flatMap{$0}
}
I created this repo with swift 5 is very easy to use
all is already set up. you have just to change the IAP ids
The Github repo

How to find the recently viewed records using objective C

Im working on recently viewed functionality, I have to create one model class of History. In history i have FileName,Title,ActivityName. Im using 2 methods to store the filename and title.
History.h
-(BOOL)history:(NSString *)sFile activityName:(NSString *)activityName title:(NSString *)title GID_ID:(NSString *)dataGID_ID;
-(id)getHistoryInstance;
-(BOOL)addNewHistory:(Histrory *)history;
-(NSMutableArray *)recentlyViewedDict;
History.m
+(Histrory *)getSharedInstance{
if (!sharedInstance) {
sharedInstance = [[super allocWithZone:NULL]init];
[sharedInstance recentlyViewedDict];
}
return sharedInstance;
}
-(NSMutableArray *)recentlyViewedDict {
return recentlyViewedDict;
}
-(BOOL)history:(NSString *)sFile activityName:(NSString *)activityName title:(NSString *)title GID_ID:(NSString *)dataGID_ID
{
_sFile = sFile;
_titleName = title ;
_dataGID_ID = dataGID_ID;
_activityName = activityName;
[self performSelector:#selector(addNewHistory:) withObject:self afterDelay:0.1];
return YES;
}
-(id)getHistoryInstance {
NSLog(#"RECENTLY VIEWED DICY %#", recentlyViewedDict);
if ([recentlyViewedDict count] == 0) {
recentlyViewedDict = [[NSMutableArray alloc]init];
}
else {
return recentlyViewedDict;
}
return recentlyViewedDict;
}
-(BOOL)addNewHistory:(Histrory *)his {
BOOL val = false;
recentlyViewedDict = [self getHistoryInstance];
if ([recentlyViewedDict count] != 0) {
for (int i = 0 ; i < [recentlyViewedDict count]; i++) {
Histrory *one = (Histrory *) recentlyViewedDict[i];
if ([his.getData_GIDID isEqualToString:one.getData_GIDID]) {
val = false;
[recentlyViewedDict removeObjectAtIndex:i];
}
}
}
else {
NSString *addData = [NSString stringWithFormat:#"%#,%#,%#,%#",his.getsFile,his.getTitle,his.getAcivityName,his.getData_GIDID];
[recentlyViewedDict addObject:addData];
}
if ([recentlyViewedDict count] > 11) {
[recentlyViewedDict removeObjectAtIndex:0];
}
NSLog(#"Recently Viewed %#", recentlyViewedDict);
return YES;
}
In this every time i have to store only 1 file.I want to store at least 10 records, if 11 record inserting then 1 record will be deleted using below method.
if ([recentlyViewedDict count] > 11) {
[recentlyViewedDict removeObjectAtIndex:0];
}
How can i store each time recent record.
ContactDetails.m
historyObj = [[Histrory alloc]init];
[historyObj history:sFile activityName:activityName title:contactName GID_ID:contactGID_ID];
Im calling this method every time to visit details classes. this method works only one time like, it will store only first record, you are visited second time it is showing nil value. How can store the multiple detail classes to store each record.thanks in advance.

(Objective-c/Mac OSX) How to distinguish managed AD users (AD user create mobile card) from local users on Mac OSX

<\RESOLVED>, Please see the first reply
My mac(10.9) has joined into a AD domain. In my program, I tried to recognize whether the current login user is local account or AD user. I can successfully distinguish them by using the following code.
+ (bool)isLocalUser:(NSString*)user
{
NSError *dirSearchError = nil;
ODRecord *foundUser = findUser(user, &dirSearchError);
if(foundUser !=nil)
{
return YES;
}else
{
return NO;
}
}
ODRecord *findUser(NSString *user, NSError **error)
{
NSLog(#"[MacLogonUI] findUser");
ODNode *searchNode = [ODNode nodeWithSession: [ODSession defaultSession]
type: kODNodeTypeLocalNodes
error: error];
if (searchNode == nil) {
return nil;
}
NSDictionary *nodeInfo = [searchNode nodeDetailsForKeys:nil error:error];
/* query this node for the user record we're interested in.
* We only need one result, which is why maximumResults is set to 1.
*/
ODQuery *userSearch = [ODQuery queryWithNode: searchNode
forRecordTypes: kODRecordTypeUsers
attribute: kODAttributeTypeRecordName
matchType: kODMatchEqualTo
queryValues: user
returnAttributes: kODAttributeTypeStandardOnly
maximumResults: 1
error: error];
if (userSearch == nil) {
return nil;
}
/* For this example we'll use a synchronous search. This could take a while
* so asynchronous searching is preferable.
*/
NSArray *foundRecords = [userSearch resultsAllowingPartial: NO error: error];
if (foundRecords == nil || [foundRecords count] == 0) {
return nil;
}
ODRecord *userRecord = [foundRecords objectAtIndex: 0];
return [[userRecord retain] autorelease];
}
While when the AD user create a mobile card, it is viewed as a managed user(from the System preference -> Users & Groups). The code also recognize this kind of AD user as local. How to deal with this kind of situation?
Do you guys have any idea of this problem?
I have solved this problem by myself. Hope the following code helps:
#import "DasUser.h"
#import <OpenDirectory/OpenDirectory.h>
#import <Collaboration/Collaboration.h>
#implementation DasUser
+ (bool)isLocalUser:(NSString*)user
{
NSError *dirSearchError = nil;
ODRecord *foundUser = findUser(user, &dirSearchError);
if(foundUser !=nil)
{
return YES;
}else
{
return NO;
}
}
ODRecord *findUser(NSString *user, NSError **error)
{
NSLog(#"[MacLogonUI] findUser");
CSIdentityAuthorityRef defaultAuthority = CSGetManagedIdentityAuthority();
CSIdentityClass identityClass = kCSIdentityClassUser;
CSIdentityQueryRef query = CSIdentityQueryCreate(NULL, identityClass, defaultAuthority);
CFErrorRef err = NULL;
CSIdentityQueryExecute(query, 0, &err);
CFArrayRef results = CSIdentityQueryCopyResults(query);
int numResults = CFArrayGetCount(results);
NSMutableArray * managedUsers = [NSMutableArray array];
for (int i = 0; i < numResults; ++i) {
CSIdentityRef identity = (CSIdentityRef)CFArrayGetValueAtIndex(results, i);
CBIdentity * identityObject = [CBIdentity identityWithCSIdentity:identity];
NSString* posixName = [identityObject posixName];
[managedUsers addObject:posixName];
}
CFRelease(results);
CFRelease(query);
ODNode *searchNode = [ODNode nodeWithSession: [ODSession defaultSession]
type: kODNodeTypeLocalNodes
error: error];
if (searchNode == nil) {
return nil;
}
/* query this node for the user record we're interested in.
* We only need one result, which is why maximumResults is set to 1.
*/
ODQuery *userSearch = [ODQuery queryWithNode: searchNode
forRecordTypes: kODRecordTypeUsers
attribute: kODAttributeTypeRecordName
matchType: kODMatchEqualTo
queryValues: user
returnAttributes: kODAttributeTypeStandardOnly
maximumResults: 1
error: error];
if (userSearch == nil) {
return nil;
}
/* For this example we'll use a synchronous search. This could take a while
* so asynchronous searching is preferable.
*/
NSArray *foundRecords = [userSearch resultsAllowingPartial: NO error: error];
if([foundRecords count]>0)
{
NSString *nameStr = [foundRecords[0] recordName];
NSLog(#"[MacLogonUI] findUser nameStr %#", nameStr);
int j;
for( j = 0; j<[managedUsers count]; j++)
{
if([nameStr isEqualToString:managedUsers[j]])
{
break;
}
}
if(j<[managedUsers count])
{
foundRecords = nil;
}
}
if (foundRecords == nil || [foundRecords count] == 0) {
return nil;
}
ODRecord *userRecord = [foundRecords objectAtIndex: 0];
return [[userRecord retain] autorelease];
}
#end
While when network of the mac is disconnected. The managed user can not be listed. Is there anybody has any idea of this?

Programmatically create a group in contacts

How to programmatically add a new group to the iPhone contact using AddressBook framework?
First look and see if it exists, and if not, create it:
bool foundIt = NO;
// Protective - did we just not find it, or lose it?
CFArrayRef groups = ABAddressBookCopyArrayOfAllGroups(addrBook);
CFIndex numGroups = CFArrayGetCount(groups);
for(CFIndex idx=0; idx<numGroups; ++idx) {
ABRecordRef groupItem = CFArrayGetValueAtIndex(groups, idx);
CFStringRef name = (CFStringRef)ABRecordCopyValue(groupItem, kABGroupNameProperty);
//NSLog(#"Look at group named %#", name);
bool isMatch = [newName isEqualToString:(NSString *)name];
CFRelease(name);
if(isMatch) {
// NSLog(#"FOUND THE GROUP ALREADY!");
groupNum = [NSNumber numberWithInt:ABRecordGetRecordID(groupItem)];
[self setObject:groupNum forKey:kGroupID];
foundIt = YES;
break;
}
}
CFRelease(groups);
if(!foundIt) {
// lets create one
ABRecordRef groupItem = ABGroupCreate();
ABRecordSetValue(groupItem, kABGroupNameProperty, (CFStringRef *)newName, &error);
if(!error) {
ABAddressBookAddRecord (addrBook, groupItem, &error); // bool ret =
ABAddressBookSave(addrBook, &error);
groupNum = [NSNumber numberWithInt:ABRecordGetRecordID(groupItem)];
//NSLog(#"FIRST groupNumber: %#", groupNum);
[self setObject:groupNum forKey:kGroupID];
}
CFRelease(groupItem);
}

NSCFString leak inVolving NSString

I am getting leak at:
NSString *firstNameStr = [NSString stringWithFormat:#"%s",firstNameString];
CODE:
+(NSString *)getValueForProperty:(ABPropertyID)propertyId
forContact:(NSString *)contactId
{
if (addressBook == nil)
{
addressBook = ABAddressBookCreate();
}
ABRecordID contactIntId = [contactId intValue];
ABRecordRef person;
person = ABAddressBookGetPersonWithRecordID(addressBook, contactIntId);
CFStringRef firstName;
char *firstNameString;
firstName = ABRecordCopyValue(person, propertyId);
// Paso a char* los datos para que se puedan escribir
static char* fallback = "";
int fbLength = strlen(fallback);
int firstNameLength = fbLength;
bool firstNameFallback = true;
if (firstName != NULL)
{
firstNameLength = (int) CFStringGetLength(firstName);
firstNameFallback = false;
}
if (firstNameLength == 0)
{
firstNameLength = fbLength;
firstNameFallback = true;
}
firstNameString = malloc(sizeof(char)*(firstNameLength+1));
if (firstNameFallback == true)
{
strcpy(firstNameString, fallback);
}
else
{
CFStringGetCString(firstName, firstNameString,
10*CFStringGetLength(firstName), kCFStringEncodingASCII);
}
if (firstName != NULL)
{
CFRelease(firstName);
}
NSString *firstNameStr = [NSString stringWithFormat:#"%s",firstNameString];
free(firstNameString);
return firstNameStr;
}
That means that the object allocated at that point is leaked. In this case, most likely because you over-retained it somewhere and failed to release it.
You need to carefully examine the lifespan of that particular string and figure out where you might be overwriting the reference without a release.
Build & Analyze might help considerably.