custom Sorting objective-c OSX - objective-c

I'm trying to sort an array of version numbers that might look like this properly sorted:
1.0.1
1.1.2
1.2.0
1.10.3
2.1.1
2.2.2
2.10.2
I have an array and I do the following:
NSArray *allUpdatekeys = [allUpdatekeystmp sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
This produces a list like:
1.0.1
1.1.2
1.10.3
1.2.0
...
So I tried writing a custom selector and I got this far by looking at examples I found:
- (NSComparisonResult)versionCompare:(NSString*) secondVersion {
NSArray *secondVer = [secondVersion componentsSeparatedByString:#"."];
NSString *firstVersion = [];
NSArray *firstVer = [firstVersion componentsSeparatedByString:#"."];
NSUInteger firstPri = [firstVer[0] integerValue];
NSUInteger firstSec = [firstVer[1] integerValue];
NSUInteger firstTer = [firstVer[2] integerValue];
NSUInteger secondPri = [secondVer[0] integerValue];
NSUInteger secondSec = [secondVer[1] integerValue];
NSUInteger secondTer = [secondVer[2] integerValue];
NSLog(#"In the version compare method");
NSLog(#"first %# second %# ", self, secondVersion);
if (firstPri < secondPri) {
return NSOrderedAscending;
}
else if (firstPri secondPri) {
return NSOrderedDescending;
} else {
if (firstSec < secondSec) {
return NSOrderedAscending;
}
else if (firstSec secondSec) {
return NSOrderedDescending;
}
else {
if (firstTer < secondTer) {
return NSOrderedAscending;
}
else if (firstTer secondTer) {
return NSOrderedDescending;
}
else {
return NSOrderedSame;
}
}
} }
My question: What is the way to reference the first version? I need what essentially is the first string from the array. I have been racking my brain to understand this, but all of the examples I have found don't work either. I'm using Xcode 4.4 on 10.8 if that helps or matters.

I think localizedStandardCompare is what you're looking for:
NSArray *theArray = [NSArray arrayWithObjects:
#"1.0.1",
#"1.1.2",
#"1.2.0",
#"1.10.3",
#"2.1.1",
#"2.2.2",
#"2.10.2",
nil];
NSArray *sortedArray = [[NSArray alloc] initWithArray:[theArray sortedArrayUsingSelector:#selector(localizedStandardCompare:)]];
NSLog(#"%#", sortedArray);
Output:
(
"1.0.1",
"1.1.2",
"1.2.0",
"1.10.3",
"2.1.1",
"2.2.2",
"2.10.2"
)

Another solution to get a sorted array in which 1.2.0 is less than 1.10.3, which means that
the array is numerically sorted, is:
allUpdatekeys = [allUpdatekeystmp sortedArrayUsingFunction:cmp context:NULL];
with the function:
NSComparisonResult cmp( id val1, id val2, void *context ){
return [val1 compare:num2 options:NSNumericSearch | NSCaseInsensitiveSearch];
}

Related

How to cancel sortUsingComparator

When the array is sorting, [arr sortUsingComparator:sortByTime]
and then I wanna cancel the operation. What should I do?
I don't think this is easily possible. Presumably you are working in a concurrent environment. Then something like this should cause the sort to exit quickly. You need to sync access to the sortCancel BOOL when you set it as well, just as when you get it as below.
__block BOOL sortCancel = NO;
NSObject * lock = NSObject.new; // Sync access to sortCancel
NSArray *sortedArray = [array sortedArrayUsingComparator: ^(id obj1, id obj2) {
#synchronized ( lock ) {
// Check for cancel
if ( sortCancel ) {
// Sort has been cancelled
return (NSComparisonResult)NSOrderedSame;
}
}
// 'Normal' compare, e.g.
if ([obj1 integerValue] > [obj2 integerValue]) {
return (NSComparisonResult)NSOrderedDescending;
}
if ([obj1 integerValue] < [obj2 integerValue]) {
return (NSComparisonResult)NSOrderedAscending;
}
return (NSComparisonResult)NSOrderedSame;
}];
I did not test this, but this should either break the sort or cause it to complete quickly.
I wonder why you want to abort the sorting?

NSPredicate - predicateWithFormat insecure

I have a predicate for query in core data base but i don't know what is the correct way to validate its params?
- (void) queryToDatabaseWithStoreId:(NSInteger) storeId {
[NSPredicate predicateWithFormat:#"store.storeId = %d", storeId];
}
My question is how can i validate storeId param or what i need to use for that vulnerability to dissapear?
And if i have a list:
- (void) queryToDataBaseWithListStore:(NSArray<Store *> *) storeList {
[NSPredicate predicateWithFormat:#"store.storeId IN %#", [storeList valueForObject:#"storeId"]];
}
https://developer.apple.com/library/archive/documentation/Security/Conceptual/SecureCodingGuide/Articles/ValidatingInput.html#//apple_ref/doc/uid/TP40007246-SW3
I need avoid that:
The following commonly-used functions and methods are subject to format-string attacks:
Standard C
printf and other functions listed on the printf(3) manual page
sscanf and other functions listed on the scanf(3) manual page
syslog and vsyslog
Carbon
AEBuildDesc and vAEBuildDesc
AEBuildParameters and vAEBuildParameters
AEBuildAppleEvent and vAEBuildAppleEvent
Core Foundation
CFStringCreateWithFormat
CFStringCreateWithFormatAndArguments
CFStringAppendFormat
CFStringAppendFormatAndArguments
Cocoa
stringWithFormat:, initWithFormat:, and other NSString methods that take formatted strings as arguments
appendFormat: in the NSMutableString class
alertWithMessageText:defaultButton:alternateButton:otherButton:informativeTextWithFormat: in NSAlert
predicateWithFormat:, predicateWithFormat:arguments:, and predicateWithFormat:argumentArray: in NSPredicate
raise:format: and raise:format:arguments: in NSException
NSRunAlertPanel and other AppKit functions that create or return panels or sheets
What is the best way to avoid this attack?
I have programmed this class but i don't know if it is enough.
#implementation StringUtils
+ (BOOL) isEmpty:(id) text {
if ([text isKindOfClass:[NSNull class]]) {
return YES;
} else {
if (text) {
if ([text isKindOfClass:[NSString class]]) {
NSString *textStr = [NSString stringWithFormat:#"%#", text];
return [textStr isEqualToString:#""];
}
return YES;
} else {
return YES;
}
}
}
+ (NSString *) validateField:(id) text {
NSInteger numErrors = 0;
NSString *pattern = #"[^A-Za-z0-9-]+";
NSError *error = nil;
NSString *textValidated = #"";
if ([text isKindOfClass:[NSNumber class]]) {
textValidated = [text stringValue];
} else if ([text isKindOfClass:[NSString class]]) {
textValidated = text;
} else {
#try {
textValidated = [text stringValue];
} #catch (NSException *exception) {
numErrors=+1;
}
}
//Only numbers && chars && -
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:&error];
NSRange textRange = NSMakeRange(0, textValidated.length);
NSRange matchRange = [regex rangeOfFirstMatchInString:textValidated options:NSMatchingReportProgress range:textRange];
if (matchRange.location != NSNotFound) {
numErrors+=1;
}
//Not empty string
if ([StringUtils isEmpty:textValidated]) {
numErrors+=1;
}
if (numErrors == 0) {
return textValidated;
}
return #"";
}
+ (NSArray *) validateArrayFields:(NSArray *) list {
NSInteger *numErrors = 0;
for (id obj in list) {
if ([StringUtils isEmpty:[StringUtils validateField:obj]]) {
numErrors+=1;
}
}
if (numErrors == 0) {
return list;
}
return [[NSArray alloc] init];
}
#end
For use normal:
[NSPredicate predicateWithFormat:#"store.storeId = %#", [StringUtils validateField:storeId]];
For use with array:
[NSPredicate predicateWithFormat:#"store.storeId IN %#", [StringUtils validateArrayFields:storeId]];

Always returning null in NSString return function

I have the following code where I want to convert decimal odds to fractional odds. However the function findNearestWholeInteger always returns null.
- (NSString *)displayOddWithFormat:(NSString *)decimalOdd {
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"FractionalOdds"] == YES) {
float oddsF = decimalOdd.floatValue;
oddsF = oddsF - 1.0f;
return [self findNearestWholeInteger:oddsF andInitial:oddsF andBottom:1];
} else {
return odd;
}
}
- (NSString *)findNearestWholeInteger:(float)odds andInitial:(float)initial andBottom:(float)bottom {
NSNumber *numberValue = [NSNumber numberWithFloat:odds];
NSString *floatString = [numberValue stringValue];
NSArray *floatStringComps = [floatString componentsSeparatedByString:#"."];
if (floatStringComps.count == 1) {
return [NSString stringWithFormat:#"%.f/%.f", odds, bottom];
} else {
bottom += 1;
odds += initial;
[self findNearestWholeInteger:odds andInitial:initial andBottom:bottom];
return nil;
}
}
Any ideas where I need to adapt my code? Thanks in advance!
Don't you want:
return [self findNearestWholeInteger:odds andInitial:initial andBottom:bottom];
//return nil;
(not that I really understand what the method is doing).

Reusable method to check if all objects are unequal using valueForKey

I have been working with this method for hours. It is supposed to simply check if the attribute of the cards passed in as otherCards isEqual to the same attribute of this (self) instance of class. But I am tearing my hair out - it is giving false results
(BOOL)otherCards: (NSArray *)otherCards allHaveUnequalAttribute: (NSString *)key
{
NSArray *values = [NSArray arrayWithArray:[otherCards valueForKey:key]];
int countUnequalMatches = 0;
for (NSNumber *setValue in values) {
if (![[self valueForKey:key] isEqual:setValue]) {
countUnequalMatches++;}
}
NSLog(#"countUnequalMatches %d values count: %d", countUnequalMatches, [values count]);
if (countUnequalMatches == [values count]) return YES ?: NO;
}
It is called like this:
if ([self otherCards:otherCards allHaveUnequalAttribute:CARD_SHAPE]) {
NSLog(#"All unequal");
} else {
NSLog(#"One or more card equal");
}
I found the bug myself
if (countUnequalMatches == [values count]) return YES ?: NO;
should be:
if (countUnequalMatches == [otherCards count]) return YES ?: NO;
as I used the Set as an way to count unique items.
This is the sort of thing that predicates are very well suited to handle.
-(BOOL)otherCards: (NSArray *)otherCards allHaveUnequalAttribute: (NSString *)key
{
NSPredicate *pred = [NSPredicate predicateWithFormat:#"%K == %#", key, [self valueForKey:key]];
NSArray *equalCards = [otherCards filteredArrayUsingPredicate:pred];
return equalCards.count == 0;
}

How to return arrays object + count IOS

hi at all ,I've this code :
+(NSArray *)splatterUrls
{
NSString *jsonString = [ ApiMethod jsonOfStores];
NSDictionary *results =[jsonString objectFromJSONString];
NSArray *movieArray = [results objectForKey:#"Seasons"];
//int i=0;
// Search for year to match
for (NSDictionary *movie in movieArray)
{
NSNumber *idSplatterMovie = [movie objectForKey:#"Id"];
// NSLog(#" %#", idSplatterMovie );
NSArray *try = [movie objectForKey:#"Episodes"];
// NSLog(#"%#", try);
for (NSDictionary *op in try)
{
if([idSplatterMovie integerValue] == 46)
{
//i++;
NSArray *movieArrayString = [op objectForKey:#"Url"];
// NSLog(#" %#", movieArrayString);
return movieArrayString;
}
}
}
}
I want to return movieArrayString with all his objects and how many object contains in it. I think that I should use this method : + (id)arrayWithObjects:(const id *)objects count:(NSUInteger)count. It's possible? If yes, can you tell me how can use it?
Thank you so much!
by the way , i have to call splatterUrls method and implement in home.m that it is :
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *urlSplatter= [GetSplatterUrlsMovie splatterUrls];
NSLog(#" %#", urlSplatter);
}
Looks good as it is to me.
Do this to return your movies array, array will be equal to your movies array:
NSArray *array = [self splatterUrls];
Then to get the count/number of objects in your array do this, i is equal to the number of objects in the array:
int i = [array count];
What is the problem ??
You return a NSarray ... call the method count on your NSarray object!