I'll just show the example it's easier than words.
.h file
#interface Something : UITableViewController <UIAlertViewDelegate, GADBannerViewDelegate>
{
NSNumber *myNumber;
}
.m file
-(void) someMethod1
{
NSLog #("is it reaching here? %#", myNumber);
/// returns Null
}
-(void) someMethod2
{
FixturesObject *closestObject;
NSTimeInterval closestInterval = DBL_MAX;
for (FixturesObject *myObject in newFixtureObjectArray) {
if (myObject != nullValue) {
NSTimeInterval interval = ABS([myObject.date2 timeIntervalSinceDate:[NSDate date]]);
if (interval < closestInterval) {
closestInterval = interval;
closestObject = myObject;
}
}
roundFinder = closestObject.round;
NSNumberFormatter * f = [[NSNumberFormatter alloc] init];
[f setNumberStyle:NSNumberFormatterNoStyle];
myNumber = [f numberFromString:roundFinder];
}
NSLog(#"What is my number? %#", myNumber);
// this returns like.. 26
}
How do i pass the value from the method below to another method? It's not working for me at all.
Thank you for your time.
myNumber is part of the same object where you have the methods. You don't need to pass it anywhere. You just need to create a property setter/getter.
The method you are sending the number has to be able to accept the number as parameter, something like this:
-(void) someMethod1:(NSNumber*)number{
if (number) NSLog #("is it reaching here? %#", myNumber);
/// returns Null
}
But in this case, have a look at what #Black Frog told you. You don't really need to pass this one as it is "all around".
Related
So, I've got an sorted NSArray that contains NSString object (downloaded from a server), with the format: yyyy-MM-dd.
It's pretty much like this:
NSArray <NSString *> *dates = #[#"2017-06-25",
#"2017-06-26",
#"2017-06-27",
#"2017-06-28",
#"2017-06-30",
#"2017-07-01",
#"2017-07-02",
#"2017-07-03"];
So, today is 2017-06-29, and it's not in the array. How do I get the next nearest one? In this sample is 06-30, but it might be 07-01 if 06-30 doesn't exist...
Update
So people are asking me about what I've attempted to do. So it's like this (not very effective, but work)
Find if today is in the array (if yes, return)
Loop dates:
2.1 Convert dateString to date
2.2 Compare if date is greater than today => return if YES
If not found in step#2, return last object in dates array.
Actual code:
NSDateFormatter *formatter = [NSDateFormatter new];
formatter.dateFormat = #"yyyy-MM-dd";
NSDate *today = [NSDate date];
NSUInteger index = [dates indexOfObject:[formatter stringFromDate:today]];
// Step 1
if (index == NSNotFound) {
// Step 2: Loop converted
NSInteger i = 0;
for (NSString *date in dates) {
// Step2.1: find the next nearest date's index
NSDate *convertedDate = [formmater dateFromString:date];
// Step2.2: Compare
if ([convertedDate intervalSinceDate:today] > 0) {
index = i;
break;
}
i++;
}
// Step 3: Still not found, index = last index
if (index == NSNotFound) index = i-1;
}
return dates[index];
This doesn't look so good because I might reload the dates array pretty much. Can I have a better solution?
Your algorithm is not bad, though your code doesn't appear to implement it (no sort?). If you'd like to improve it consider this:
First there is probably little point in doing a first scan to check for an exact match - that is potentially a linear search (implemented by indexOfObject:) through an unordered array, and if it fails you have to scan again for a close match, just do them at the same time.
Second there is no advantage in sorting, which is at best O(NlogN), as a linear search, O(N), will find you the answer you need.
Here is a sketch:
Convert the date you are searching for from NSString to NSDate, call it, say, target
Set bestMatch, an NSString to nil. Set bestDelta, an NSTimeInterval, to the maximum possible value DBL_MAX.
Iterate over your dates array:
3.1. Convert the string date to an NSDate, say date
3.2. Set delta to the difference between date and target
3.3. If delta is zero you have an exact match, return it
3.4. If delta is better than bestDelta, update bestDelta and bestMatch
After iteration bestMatch is the best match or nil if there wasn't one.
That is a single iteration, O(N), early return on exact match.
HTH
Please find the simplest solution for your problem. Updated solution based on sorting order!
We can use NSPredicate Block to solve.
static NSDateFormatter* formatter = nil;
static NSDate* today = nil;
// return an NSDate for a string given in yyyy-MM-dd
- (NSDate *)dateFromString:(NSString *)string {
if (formatter == nil) {
formatter = [NSDateFormatter new];
formatter.dateFormat = #"yyyy-MM-dd";
}
return [formatter dateFromString:string];
}
// Helps to return today date.
-(NSDate*) getTodayDate {
if (today == nil) {
today = [NSDate date];
}
return today;
}
// Helps to find nearest date from Array using Predicate
-(NSString*)findNearestDate:(NSArray*)dateArray {
today = nil;
NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(NSString *dateString, NSDictionary *bind){
// this is the important part, lets get things in NSDate form so we can use them.
NSDate *dob = [self dateFromString:dateString];
NSComparisonResult result = [[self getTodayDate] compare:dob];
if (result == NSOrderedSame || result == NSOrderedAscending) {
return true;
}
return false;
}];
// Apply the predicate block.
NSArray *futureDates = [dateArray filteredArrayUsingPredicate:predicate];
if ([futureDates count] > 0) {
// Sort the Array.
futureDates = [futureDates sortedArrayUsingSelector: #selector(compare:)];
return [futureDates objectAtIndex:0];
}
return nil;
}
NSArray <NSString *> *dates = #[#"2017-06-25",
#"2017-06-26",
#"2017-06-27",
#"2017-06-28",
#"2017-06-30",
#"2017-07-01",
#"2017-07-02",
#"2017-07-03"];
NSLog(#"Nearest Date: %#", [self findNearestDate:dates]);
Answer: Nearest Date: 2017-06-30
1. Input
So you have an array of NSString like this
// input
NSArray<NSString *> * words = #[#"2017-06-25",
#"2017-06-26",
#"2017-06-27",
#"2017-06-28",
#"2017-06-30",
#"2017-07-01",
#"2017-07-02",
#"2017-07-03"];
2. Converting the array of NSString into an array of NSDate
First of all you need to convert the each input string into an NSDate
NSMutableArray<NSDate *> * dates = [NSMutableArray new];
NSDateFormatter * dateFormatter = [NSDateFormatter new];
dateFormatter.dateFormat = #"yyyy-MM-dd";
for (NSString * word in words) {
[dates addObject:[dateFormatter dateFromString:word]];
}
3. Finding the nearestDate
Now you can find the nearest date
NSDate * nearestDate = nil;
NSTimeInterval deltaForNearesttDate = 0;
NSDate * now = [NSDate new];
for (NSDate * date in dates) {
NSTimeInterval delta = fabs([date timeIntervalSinceDate:now]);
if (nearestDate == nil || (delta < deltaForNearesttDate)) {
deltaForNearesttDate = delta;
nearestDate = date;
}
}
4. Conclusion
The result is into the nearestDate variable so
NSLog(#"%#", nearestDate);
Wed Jun 28 00:00:00 2017
This question already has answers here:
Sorting two NSArrays together side by side
(4 answers)
Closed 6 years ago.
I have 2 NSMutableArrays declared. One is filled with names and then another one is filled with string values of NSDate.
I want to sort both of them according to the date in the second one. For example if element 3 in the date array becomes element 0 I want the same to happen for the name array.
What is the easiest way to do this? I know how to sort the date array just not the corresponding name array!
(Objective-C Please!)
Sorting 2 arrays and keeping them in sync is a pain. You basically have to sort them by hand.
Probably the easiest way to do this is to create an array of dictionaries where each dictionary contains a data and a name.
Then sort the array of dictionaries by date.
EDIT:
Here is the code for creating custom objects containing a name and a date. There is code to sort by date as well as code to sort by name:
/**
The thing class has a property date and a property name.
It is purely for creating sorted arrays of objects
*/
#interface Thing : NSObject
#property (nonatomic, strong) NSDate *date;
#property (nonatomic, strong) NSString *name;
#end
#implementation Thing
/**
This is a dummy init method that creates a Thing ojbect with a random name and date
*/
- (instancetype) init {
self = [super init];
if (!self) return nil;
NSString *letters = #"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
NSMutableString *temp = [NSMutableString new];
for (int x = 0; x < 10; x++) {
unichar aChar = [letters characterAtIndex:arc4random_uniform(26)];
[temp appendFormat: #"%C", aChar];
}
self.name = [temp copy];
//Create a random date
uint32 halfMax = 2000000000;
uint32 max = halfMax * 2;
int32_t value = arc4random_uniform(max) - halfMax;
NSTimeInterval now = [[NSDate date] timeIntervalSinceReferenceDate];
self.date = [NSDate dateWithTimeIntervalSinceReferenceDate: now + value];
return self;
}
- (NSString *) description {
return [NSString stringWithFormat: #"Name: %# Date: %#", self.name, self.date];
}
#end
int main(int argc, const char * argv[]) {
#autoreleasepool {
//Create an array of Thing objects
const int count = 50;
NSMutableArray *thingArray = [NSMutableArray arrayWithCapacity: count];
for (int x = 0; x < count; x++) {
thingArray[x] = [[Thing alloc] init];
}
#if 1
//Sort by date, ascending
[thingArray sortUsingComparator:^NSComparisonResult(Thing *obj1,
Thing *obj2) {
NSComparisonResult bigger =
[obj1.date timeIntervalSinceReferenceDate] <
[obj2.date timeIntervalSinceReferenceDate] ?
NSOrderedAscending : NSOrderedDescending;
return bigger;
}];
#else
//Sort by name
[thingArray sortUsingComparator:^NSComparisonResult(Thing *obj1,
Thing *obj2) {
return [obj1.name compare: obj2.name];
}];
#endif
NSLog(#"%#", thingArray);
}
return 0;
}
I'm checking is first letter of string is 0, if it is remove it and call again method to check is there is still 0. I've debugged this and it seems like when it accomplish number without 0, it goes backwards. Code:
-(NSString *)deleteZerosOnFirst:(NSString *)card
{
NSString *firstLetter = [card substringToIndex:1];
if ([firstLetter isEqualToString:#"0"]) {
card = [card substringFromIndex:1];
[self deleteZerosOnFirst:card];
NSLog(#"CARD: %#", card);
return card;
}
else {
NSLog(#"CARD: %#", card);
return card;
}
}
The main problem is that you're not using the result of the recursion. The line of code where you call yourself should say this:
card = [self deleteZerosOnFirst:card];
Also, you're calling deleteZerosOnFirst before you do the NSLog. Reverse the order of these two lines. That will at least give you your debug output in the right sequence.
Here's your recursive call:
[self deleteZerosOnFirst:card];
That doesn't modify the string that card references. It creates and returns a new string. You're ignoring the returned string. You want this:
card = [self deleteZerosOnFirst:card];
But this is really a lot simpler:
#implementation NSString (withoutLeadingZeroes)
- (NSString *)withoutLeadingZeroes {
NSString *s = self;
while ([s hasPrefix:#"0"]) {
s = [s substringFromIndex:1];
}
return s;
}
#end
I have a method that I call that calculates the Sunrise, Noon and Sunset for any given day. I pass the method the day date as a Julian.
The method need to return the three numbers or strings: Sunrise, Noon and Sunset.
I am trying to call it as follows:
ClassSolarCalculations *LINK = [[ClassSolarCalculations alloc] init];
NSString dateSunrise= [[NSString alloc] initWithFormat:#"%f", [LINK CalculateSunrise: Julian]];
where the Method reads:
(NSDictionary *) CalculateSunrise: (double) Julian;
NSDictionary *returnTimes = [NSDictionary initWithObjectsAndKeys: SunriseText, #"Sunrise", NoonText, "#Noon", SunsetText, #"Sunset", nil];
return returnTimes;
I can this approach to work to return a single value but would like to return all three in one go rather than fudge the solution by calling variants of the routine three times…
Lots of things should be changed here:
method and variable names should start with lowercase letters and use camel case.
Rename your CalculateSunrise: method since it will return more values. Maybe calculateSunTimes:.
Since your method returns an NSDictionary you handling of the return needs to be different.
Try this:
ClassSolarCalculations *link = [[ClassSolarCalculations alloc] init];
NSDictionary *times = [link calculateSunTimes:julian];
NSString *sunrise = times[#"sunrise"];
NSString *noon = times[#"noon"];
NSString *sunset = times[#"sunset"];
Your method would be something like:
- (NSDictionary *)calculateSunTimes:(double)julian {
// calculate the three values:
return #{ #"sunrise" : sunriseText, #"sunset" : sunsetText, #"noon" : noonText };
}
Notice the use of modern Objective-C syntax.
Hello I am working on a project and I am trying to add an NSUInteger to an NSMutableArray. I am new to Objective-C and C in general. When I run the app NSLog displays null.
I'd appreciate any help anyone is able to provide.
Here is my code
-(NSMutableArray *)flipCardAtIndex:(NSUInteger)index
{
Card *card = [self cardAtIndex:index];
[self.flipCardIndexes addObject:index];
if(!card.isUnplayable)
{
if(!card.isFaceUp)
{
for(Card *otherCard in self.cards)
{
if(otherCard.isFaceUp && !otherCard.isUnplayable)
{
int matchScore = [card match:#[otherCard]];
if(matchScore)
{
otherCard.unplayable = YES;
card.unplayable = YES;
self.score += matchScore * MATCH_BONUS;
}
else
{
otherCard.faceUp = NO;
self.score -=MISMATCH_PENALTY;
}
break;
}
}
self.score -=FLIP_COST;
}
card.faceUp = !card.isFaceUp;
}
NSLog(#"%#",self.flipCardIndexes[self.flipCardIndexes.count-1]);
return self.flipCardIndexes;
}
NSArray (along with its subclass NSMutableArray) only supports objects, you cannot add native values to it.
Check out the signature of -addObject:
- (void)addObject:(id)anObject
As you can see it expects id as argument, which roughly means any object.
So you have to wrap your integer in a NSNumber instance as follows
[self.flipCardIndexes addObject:#(index)];
where #(index) is syntactic sugar for [NSNumber numberWithInt:index].
Then, in order to convert it back to NSUInteger when extracting it from the array, you have to "unwrap" it as follows
NSUInteger index = [self.flipCardIndexes[0] integerValue]; // 0 as example
You can only add objects to NSMutableArrays. The addObject accepts objects of type id, which means it will accept an object.
NSIntegers and NSUIntegers, however, are not objects. They are just defined to be C style variables.
#if __LP64__ || NS_BUILD_32_LIKE_64
typedef long NSInteger;
typedef unsigned long NSUInteger;
#else
typedef int NSInteger;
typedef unsigned int NSUInteger;
#endif
As you can see, they are just defined to be ints and longs based on a typedef macro.
To add this to your array, you need to first convert it to an object. NSNumber is the Objective C class that allows you to store a number of any type. To make the NSNumber, you will want to you the numberWithInt method, passing your variable as the parameter.
NSNumber *number = [NSNumber numberWithInt:card];
Now that your variable is wrapped in an object, you can add it to the array.
[self.flipCardIndexes addObject:number];
Finally, if you want to retrieve the element at a future time, you have to remove the object and then convert it back to an int value you can use. Call
NSNumber *number = [self.flipCardIndexes objectAtIndex:index];
Where index is the index of the card you are trying to retrieve. Next, you have to convert this value to an integer by calling integerValue.
NSUInteger *value = [number integerValue];