How can I compare installed iOS version with the latest iOS version programatically using objective-c?
You have to take new version number from web service.This is because if you want to update app from app store then you just need to increase your app version from your pannel and you will get it in web service and then you can check it like this (call this method by passing web service version) :-
(BOOL)isUpdateAvailable:(NSString*)latestVersion
{
NSString *currentAppVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleShortVersionString"];
NSArray *myCurrentVersion = [currentAppVersion componentsSeparatedByString:#"."];
NSArray *myLatestVersion = [latestVersion componentsSeparatedByString:#"."];
NSInteger legthOfLatestVersion = myLatestVersion.count;
NSInteger legthOfCurrentVersion = myCurrentVersion.count;
if (legthOfLatestVersion == legthOfCurrentVersion)
{
for (int i=0; i<myLatestVersion.count; i++)
{
if ([myCurrentVersion[i] integerValue] < [myLatestVersion[i] integerValue])
{
return true;
}
else if ([myCurrentVersion[i] integerValue] == [myLatestVersion[i] integerValue])
{
continue;
}
else
{
return false;
}
}
return false;
}
else
{
NSInteger count = legthOfCurrentVersion > legthOfLatestVersion ? legthOfLatestVersion : legthOfCurrentVersion;
for (int i=0; i<count; i++)
{
if ([myCurrentVersion[i] integerValue] < [myLatestVersion[i] integerValue])
{
return true;
}
else if([myCurrentVersion[i] integerValue] > [myLatestVersion[i] integerValue])
{
return false;
}
else if ([myCurrentVersion[i] integerValue] == [myLatestVersion[i] integerValue])
{
continue;
}
}
if (legthOfCurrentVersion < legthOfLatestVersion)
{
for (NSInteger i=legthOfCurrentVersion; i<legthOfLatestVersion; i++)
{
if ([myLatestVersion[i] integerValue] != 0)
{
return YES;
}
}
return NO;
}
else
{
return NO;
}
}
}
This will return bool value if it will return YES then you will have new version of your app and if NO then your app has updated version.
- (id)objectAtIndexSafe:(NSUInteger)index
{
if (index < [self count]) {
return [self objectAtIndexSafe:index];
}else {
TTSafeKitAssert(NO, #"unsafe");
return nil;
}
}
TTSafeKitAssert : send dumped threads info(use PlCashReporter) to sever,but when objectAtIndexSafe called in for in,TTSafeKitAssert will send so many times . How can i just send once in this situation!
If it is a category:
- (id)objectAtIndexSafe:(NSUInteger)index
{
if (index < [self count]) {
return [self objectAtIndex:index];
}else {
TTSafeKitAssert(NO, #"unsafe");
return nil;
}
}
basically I'm using firebase to query a user's 'status' property and doing so in a do/while loop.
If the status property is free then i want to break the loop and continue with the rest of the method. If the status property is not free then I want to query firebase again for a new user until a free user is found.
My firebase code works fine outside the loop but doesn't seem to be called inside of it. Here is the loop:
__block uint32_t rando;
self.freedom = #"about to check";
do {
//check if free
[self checkIfFree:^(BOOL finished) {
if (finished) {
if ([self.freedom isEqualToString:#"free"]) {
//should break loop here
}
else if ([self.freedom isEqualToString:#"matched"]){
//get another user
do {
//picking another random user from array
rando = arc4random_uniform(arraycount);
}
while (rando == randomIndex && rando == [self.randString intValue]);
self.randString = [NSString stringWithFormat:#"%u", rando];
[users removeAllObjects];
[users addObject:[usersArray objectAtIndex:rando]];
self.freeUser = [users objectAtIndex:0];
//should repeat check here but doesn't work
}
else{
NSLog(#"error!");
}
}
else{
NSLog(#"not finished the checking yet");
}
}];
} while (![self.freedom isEqual: #"free"]);
And here's my firebase code:
-(void)checkIfFree:(myCompletion) compblock{
self.freeUserFB = [[Firebase alloc] initWithUrl:[NSString stringWithFormat: #"https://skipchat.firebaseio.com/users/%#", self.freeUser.objectId]];
[self.freeUserFB observeEventType:FEventTypeValue withBlock:^(FDataSnapshot *snapshot)
{
self.otherStatus = snapshot.value[#"status"];
NSLog(#"snapshot info %#", snapshot.value);
if ([self.otherStatus isEqualToString:#"free"]) {
self.userIsFree = YES;
self.freedom = #"free";
}
else{
self.userIsFree = NO;
self.freedom = #"matched";
}
compblock(YES);
}];
}
Thanks!
I am not sure I understand correctly your question.
If you want to run your completion code again till some condition is matched (in this case [self.freedom isEqualToString:#"free"]) you can do the following (removing the do - while):
void( ^ myResponseBlock)(BOOL finished) = ^ void(BOOL finished) {
if (finished) {
if ([self.freedom isEqualToString: #"free"]) {
return;
} else if ([self.freedom isEqualToString: #"matched"]) {
//get another user
do {
//picking another random user from array
rando = arc4random_uniform(arraycount);
}
while (rando == randomIndex && rando == [self.randString intValue]);
self.randString = [NSString stringWithFormat: #"%u", rando];
[users removeAllObjects];
[users addObject:usersArray[rando]];
self.freeUser = users.firstObject;
// Schedule another async check
[self checkIfFree: myResponseBlock];
} else {
NSLog(#"error!");
}
} else {
NSLog(#"not finished the checking yet");
}
};
[self checkIfFree: myResponseBlock];
Need some help with a complex issue on my paginated scrollview. Im adding multiple pages with tableviews and some more data that could be heavy for memory. But it building up memory with each scroll. I would like my code to only add a subview once and on scroll replace it and release the old on (im using ARC). But the memory is building up, i think its because its adding the subview multiple times.
- (void)scrollViewDidScroll:(UIScrollView *)sender
{
#synchronized(self) {
#autoreleasepool {
CGFloat pageWidth = mainScrollView.frame.size.width;
NSInteger page = round(mainScrollView.contentOffset.x / pageWidth);
int scrollOffset = (page * barWidth)-(mainScrollView.bounds.size.width/2);
if (scrollOffset<=0) {
scrollOffset = 0;
} else if (scrollOffset >= (pageIndicatorScrollView.contentSize.width - pageIndicatorScrollView.frame.size.width)) {
scrollOffset = (pageIndicatorScrollView.contentSize.width - pageIndicatorScrollView.frame.size.width);
}
[pageIndicatorScrollView setContentOffset:CGPointMake(scrollOffset, 0) animated:YES];
if(page < 0)
{
page = 0;
}
if(page >= [categoryScrollersArray count])
{
page = [categoryScrollersArray count] - 1;
}
//page = page +1;
//////////NSLog(#"page = %d",page);
// don't create or delete pages while rotating
if (!isRotating) {
if([categoryScrollersArray count] == 1)
{
if([categoryScrollersArray objectAtIndex:0] == [NSNull null])
{
[self loadScrollViewWithPage:0];
}
}
else if([categoryScrollersArray count] == 2)
{
if([categoryScrollersArray objectAtIndex:0] == [NSNull null])
{
[self loadScrollViewWithPage:0];
}
if([categoryScrollersArray objectAtIndex:1] == [NSNull null])
{
[self loadScrollViewWithPage:1];
}
}
else
{
if(page - 1 < 0)
{
if([categoryScrollersArray objectAtIndex:0] == [NSNull null])
{
[self loadScrollViewWithPage:0];
}
if([categoryScrollersArray objectAtIndex:1] == [NSNull null])
{
[self loadScrollViewWithPage:1];
}
}
else
{
if([categoryScrollersArray objectAtIndex:page - 1] == [NSNull null])
{
[self loadScrollViewWithPage:page - 1];
}
if([categoryScrollersArray objectAtIndex:page] == [NSNull null])
{
[self loadScrollViewWithPage:page];
}
if(page + 1 < [categoryScrollersArray count])
{
if([categoryScrollersArray objectAtIndex:page + 1] == [NSNull null])
{
[self loadScrollViewWithPage:page + 1];
}
}
}
if(page -2 >= 0 )
{
if([categoryScrollersArray objectAtIndex:page -2] != [NSNull null])
{
UIView *u = [categoryScrollersArray objectAtIndex:page-2];
//////////NSLog(#"remove page = %d",page-2);
[u removeFromSuperview];
if (page-2 < [categoryScrollersArray count]) {
if ([categoryScrollersArray objectAtIndex:page-2] == nil) {
[self showUnexpectedBehaviorAlertWithTest:#"An unknown error occured, please reopen the questionnaire. (1307)"];
}
else {
[categoryScrollersArray replaceObjectAtIndex:page-2 withObject:[NSNull null]];
}
}
else {
[self showUnexpectedBehaviorAlertWithTest:#"An unknown error occured, please reopen the questionnaire. (1314)"];
}
}
}
if(page +2 < [categoryScrollersArray count])
{
if([categoryScrollersArray objectAtIndex:page +2] != [NSNull null])
{
UIView *u = [categoryScrollersArray objectAtIndex:page+2];
// [u removeObserver:u.self forKeyPath:#"doReload"];
//////////NSLog(#"remove page = %d",page+2);
[u removeFromSuperview];
if (page+2 < [categoryScrollersArray count]) {
if ([categoryScrollersArray objectAtIndex:page+2] == nil) {
[self showUnexpectedBehaviorAlertWithTest:#"An unknown error occured, please reopen the questionnaire. (1329)"];
}
else {
[categoryScrollersArray replaceObjectAtIndex:page+2 withObject:[NSNull null]];
}
}
else {
[self showUnexpectedBehaviorAlertWithTest:#"An unknown error occured, please reopen the questionnaire. (1337)"];
}
}
}
}
}
[self changeProgressBar:page];
// ////////NSLog(#"viewControllers are %#",viewControllers);
// ////////NSLog(#"questionsScroll.subviews %#",questionsScroll.subviews);
}
}
}
And the other function:
- (void)loadScrollViewWithPage:(int)page
{
if (page < 0)
return;
if (page >= [categoryScrollersArray count])
return;
//Categories * anCat;
//anCat = [catArray objectAtIndex:page];
// replace the placeholder if necessary
CategoryScrollerView *catScroll = [categoryScrollersArray objectAtIndex:page];
if ((NSNull *)catScroll == [NSNull null])
{
Step *aStep = [steps objectAtIndex:page];
NSString *coder = [[NSString alloc] init];
if ([self.visit.savedStatus integerValue] == 2 && [self.visit.state integerValue] == 1) {
coder = #"SAVED";
} else {
coder = #"OPEN";
}
NSString *questCode = [NSString stringWithFormat:#"%#",self.visit.questionnaire.version];
catScroll = [[CategoryScrollerView alloc] initWithFrame:mainScrollView.frame andStep:aStep andDelegate:self andStepname:aStep.name andVisitcode:coder andQuestionnairecode:questCode];
catScroll.autoresizesSubviews = YES;
catScroll.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin;
[self setNextBtnTitleForPage:page andView:catScroll];
if (page < [categoryScrollersArray count]) {
if ([categoryScrollersArray objectAtIndex:page] == nil) {
[self showUnexpectedBehaviorAlertWithTest:#"An unknown error occured, please reopen the questionnaire. (1101)"];
}
else {
[categoryScrollersArray replaceObjectAtIndex:page withObject:catScroll];
}
}
else {
[self showUnexpectedBehaviorAlertWithTest:#"An unknown error occured, please reopen the questionnaire. (1108)"];
}
}
// add the controller's view to the scroll view
if (catScroll.superview == nil)
{
CGRect frame = mainScrollView.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
catScroll.frame = frame;
[mainScrollView addSubview:catScroll];
// NSDictionary *numberItem = [self.contentList objectAtIndex:page];
// controller.numberImage.image = [UIImage imageNamed:[numberItem valueForKey:ImageKey]];
// controller.numberTitle.text = [numberItem valueForKey:NameKey];
}
}
Doing this inside one view controller is going to be really complex. Especially if you're trying to do all the tableview datasource stuff in there too.
You would be much better off using a UIPageViewController.
It is a container controller (a lot like UINavigationController or UITabBarController) that is used to display view controllers in a paged scroll view type of view.
There are some tutorials here about using UIPageViewController. http://www.raywenderlich.com/?s=uipageviewcontroller&cof=FORID%3A10
Essentially you pass a different table view controller in for each page. It takes a bit of settings up but once it's done it will help make it much easier and will keep memory usage down.
There are lots more tutorials out there too... http://www.appcoda.com/uipageviewcontroller-tutorial-intro/
Also, you don't have to make it full screen. You can use the Page View Controller for only the part of the screen that you want to scroll.
I've been trying to sort an NSArray of NSDictionaries using a comparator, but I cannot seem to get the output I desire.
The output I'm trying to achieve is that A-Z usernames should come first in the sorted array, then usernames that start with a digit should come second in the sorted array, and lastly usernames that start with an underscore should be last in the sorted array. Any help is truly appreciated!
EDIT: It should be sorted so it looks consistent through the whole NSArray so that: _Anna comes before _Bob and _11Bob comes before _12Cary but after _09Bob
Example of desired output I'm looking for:
(
{
username = abcd;
},
{
username = Anna;
},
{
username = 01Bob;
},
{
username = 02Tob;
},
{
username = 03ZED;
},
{
username = 04_Hob;
},
{
username = 04_sob;
},
{
username = "_anna";
},
{
username = "_bob";
},
{
username = "_boc";
},
{
username = "_bocd12";
},
{
username = "_bocd13";
}
{
username = _01Bob;
},
{
username = _02Tob;
},
)
I hope that makes sense now.
Sample NSDictionary with an NSArray of NSDictionaries:
NSDictionary *dictionary = #{#"users":#[#{#"username":#"191anna"},#{#"username":#"_091bob"},#{#"username":#"Bob"},#{#"username":#"charlie"}]};
I'm trying by using this comparator:
NSArray *array = [[dictionary objectForKey:#"users"] sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2)
{
NSString *f1 = [obj1 objectForKey:#"username"];
NSString *f2 = [obj2 objectForKey:#"username"];
NSString *s1 = [[obj1 objectForKey:#"username"]substringFromIndex:1];
NSString *s2 = [[obj2 objectForKey:#"username"]substringFromIndex:1];
if ([s1 rangeOfCharacterFromSet:[NSCharacterSet decimalDigitCharacterSet]].location == [s2 rangeOfCharacterFromSet:[NSCharacterSet decimalDigitCharacterSet]].location)
{
return [f1 localizedCaseInsensitiveCompare:f2];
}
else if ([s1 rangeOfCharacterFromSet:[NSCharacterSet decimalDigitCharacterSet]].location != [s2 rangeOfCharacterFromSet:[NSCharacterSet decimalDigitCharacterSet]].location)
{
return [f1 localizedCaseInsensitiveCompare:f2];
if ([s1 rangeOfCharacterFromSet:[NSCharacterSet decimalDigitCharacterSet]].location == NSNotFound)
{
return NSOrderedDescending;
}
}
return NSOrderedAscending;
}];
But it gives me the following (not the way I want) sorted NSArray:
(
{
username = "_091bob";
},
{
username = 191anna;
},
{
username = Bob;
},
{
username = charlie;
}
)
Here's what I came up with. It's a touch long because it requires quite a bit of logic. It can likely be optimized further:
My Set Up:
NSArray * usernames = #[#"191anna", #"abcd", #"Anna", #"01Bob", #"02Tob", #"03ZED", #"04_rob", #"_anna", #"_bob", #"_boc", #"_bocd12", #"_bocd13", #"_01Bob", #"_02Tob"];
NSMutableArray * users = [NSMutableArray array];
for (NSString * username in usernames) {
[users addObject:#{#"username":username}];
}
NSDictionary * dictionary = #{#"users":users};
And The Sort:
NSArray *sortedArray = [dictionary[#"users"] sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2)
{
NSString *nameOne = obj1[#"username"];
NSString *nameTwo = obj2[#"username"];
NSString *startOne;
NSString *startTwo;
NSInteger currentIndex = 0;
NSInteger maxIndex = (nameOne.length < nameTwo.length) ? nameOne.length : nameTwo.length;
// Get our first differentiating letter
do {
if (currentIndex < maxIndex) {
startOne = [nameOne substringWithRange:NSMakeRange(currentIndex, 1)];
startTwo = [nameTwo substringWithRange:NSMakeRange(currentIndex, 1)];
currentIndex++;
}
else {
// Names are equal up to max length. Same length is same, else shorter word ascending. (bob above bobb)
if (nameOne.length == nameTwo.length) {
return NSOrderedSame;
}
else {
return (nameOne.length < nameTwo.length) ? NSOrderedAscending : NSOrderedDescending;
}
}
} while ([startOne isEqualToString:startTwo]);
// Prioritize underscores to bottom
NSCharacterSet * underscoreCharSet = [NSCharacterSet characterSetWithCharactersInString:#"_"];
NSRange underscoreRangeOne = [startOne rangeOfCharacterFromSet:underscoreCharSet];
NSRange underscoreRangeTwo = [startTwo rangeOfCharacterFromSet:underscoreCharSet];
if (underscoreRangeOne.length > 0 || underscoreRangeTwo.length > 0) {
// Something is underscored, put it on the bottom
return (underscoreRangeOne.length > 0) ? NSOrderedDescending : NSOrderedAscending;
}
// Prioritize numbers to bottom
NSRange decimalRangeOne = [startOne rangeOfCharacterFromSet:[NSCharacterSet decimalDigitCharacterSet]];
NSRange decimalRangeTwo = [startTwo rangeOfCharacterFromSet:[NSCharacterSet decimalDigitCharacterSet]];
if (decimalRangeOne.length > 0 || decimalRangeTwo.length > 0) {
// Something is numbered, put it on the bottom
if (decimalRangeOne.length == decimalRangeTwo.length) {
return (startOne.intValue > startTwo.intValue) ? NSOrderedDescending : NSOrderedAscending;
}
else if (decimalRangeOne.length > decimalRangeTwo.length) {
return NSOrderedDescending;
}
else if (decimalRangeTwo.length > decimalRangeOne.length) {
return NSOrderedAscending;
}
}
// Now, sort alphabetically
return [nameOne localizedCaseInsensitiveCompare:nameTwo];
}];
NSLog(#"SortedArray: %#", sortedArray);
Will log as:
abcd,
Anna,
01Bob,
02Tob,
03ZED,
"04_rob",
191anna,
"_anna",
"_bob",
"_boc",
"_bocd12",
"_bocd13",
"_01Bob",
"_02Tob"
You can optimize this further, but your sort logic would be like below.
NSArray *sorted = [array sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
NSString *name1 = [(NSDictionary *) obj1 objectForKey:NAME];
NSString *name2 = [(NSDictionary *) obj2 objectForKey:NAME];
if ([name1 characterAtIndex:0] == '_' && [name2 characterAtIndex:0] == '_')
{
return [name1 compare:name2 options:NSCaseInsensitiveSearch];
}
else if ([name1 characterAtIndex:0] == '_')
{
return NSOrderedDescending;
}
else if ([name2 characterAtIndex:0] == '_')
{
return NSOrderedAscending;
}
else if (([name1 intValue] && [name2 intValue]) || ([name1 characterAtIndex:0] == '0' && [name2 characterAtIndex:0] == '0'))
{
return [name1 compare:name2 options:NSCaseInsensitiveSearch];
}
else if ([name1 intValue] >0 || [name1 characterAtIndex:0] == '0')
{
return NSOrderedDescending;
}
else if ([name2 intValue]>0 || [name2 characterAtIndex:0] == '0')
{
return NSOrderedAscending;
}
else
{
return [name1 compare:name2 options:NSCaseInsensitiveSearch];
}
//return res;
}];