NSFileSystemFreeSize - nsnumber

I get a negaitve number from trying to use this function can anyone help. see code below
NSDictionary *fileAttributes = [fileManager attributesOfItemAtPath:dbPath error:Error];
NSDictionary *fileSysAttributes = [fileManager fileSystemAttributesAtPath:dbPath];
NSNumber *FileSize = [fileAttributes objectForKey:NSFileSize];
NSNumber *FreeSpace = [fileSysAttributes objectForKey:NSFileSystemFreeSize];
NSLog(#"FileSystem = %#",fileSysAttributes); // gives good values
NSLog(#"File Size = %d", [FileSize longLongValue]); // gives good values
NSLog(#"System Space = %d",[FreeSpace longLongValue]); //shows -ve for 45GB space
long long Result = FreeSpace - FileSize;
NSLog(#"Result = %d",Result);
The first and second log statements give good results but the third shows a negative number when I'm trying to use the longLongValue of FreeSpace directly

Two problems:
1) You should be using "%lld" in your NSLog format strings http://developer.apple.com/mac/library/documentation/cocoa/conceptual/Strings/Articles/formatSpecifiers.html
2) This code:
long long Result = FreeSpace - FileSize;
Is subtracting the addresses of the two NSNumber objects, not their values!
I think you mean:
long long Result = [FreeSpace longLongValue] - [FileSize longLongValue];

Related

Convert NSString to few NSIntegers

I have getting data from plist to NSString, in result I see something like this "{{1848,594},{154,176}}". What is the best way to convert every single number to separate NSInteger?
NSString *frame = [myPlistKey objectForKey:#"frame"];
How to convert frame to 4 separate integers?
In this specific case, it looks like you are trying to parse the string representation of an NSRect, in which case you can just use NSRectFromString() from the Foundation framework.
Edit:
Since you are not much specific, I will try to cover your situation. If i count with the fact you have NSString *frame filled with {{1848,594},{154,176}}:
NSString *stringWithoutLeftBracket = [frame
stringByReplacingOccurrencesOfString:#"{" withString:#""];
NSString *stringWithoutRightBracket = [stringWithoutLeftBracket
stringByReplacingOccurrencesOfString:#"}" withString:#""];
NSArray *frameArray = [stringWithoutRightBracket componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#","]];
Then you can access objects with indexes like:
NSInteger integer = [[frameArray objectAtIndex:0] integerValue];
But also you could use a for loop like this:
for (NSInteger integer in frameArray) {
// Do something
}
In my opinion you have a string made from rect, means you could convert it.

Can't clear/reset NSMutableSet?

This is what I'm trying to do. Get 7 random, non-repeating numbers each time my viewDidLoad starts. I got it to create the randoms, but I've been trying to clear the NSMutableSet when it loads to get a fresh set and I'm having trouble. The NSLog is clearly showing nothing is in the NSMutableSet, but it always comes up with the same numbers in the same order?
// Create set
NSMutableSet *mySet = [NSMutableSet setWithCapacity:6];
// Clear set
NSMutableSet *mutableSet = [NSMutableSet setWithSet:mySet];
[mutableSet removeAllObjects];
mySet = mutableSet;
NSLog(#"mutableSet: %#", mutableSet); // Shows nothing
NSLog(#"mySet: %#", mySet); // Shows nothing
// Assign random numbers to the set
while([mySet count]<=6){
int Randnum = arc4random() % 7+1;
[mySet addObject:[NSNumber numberWithInt:Randnum]];
}
NSLog(#"mySet1: %#", mySet); // Always shows 5,1,6,2,7,3,4 ???
An NS(Mutable)Set is an unordered collection, it does not preserve the order of the elements as they were inserted. So your output only shows that the set contains the
numbers from 1 to 7.
You have different options to get your expected output.
Use an NSMutableOrderedSet instead.
Use a set to keep track of the numbers that already occurred, but store the
numbers also in an array:
NSMutableArray *numbers = [NSMutableArray array];
NSMutableSet *mySet = [NSMutableSet set];
while ([numbers count] < 6) {
NSNumber *randNum = #(arc4random_uniform(7) + 1);
if (![mySet containsObject:randNum]) {
[numbers addObject:randNum];
[mySet addObject:randNum];
}
}
NSLog(#"numbers: %#", numbers);
For a small set (like 7 numbers in your case), you could simply use an array only:
NSMutableArray *numbers = [NSMutableArray array];
while ([numbers count] < 6) {
NSNumber *randNum = #(arc4random_uniform(7) + 1);
if (![numbers containsObject:randNum]) {
[numbers addObject:randNum];
}
}
NSLog(#"numbers: %#", numbers);

Creating array of quiz questions that do not repeat

I'm trying to create a basic quiz app where the questions will not repeat. I've looked at several examples and believe I should be storing the questions in an array and then removing one from the array each time its used. I've tried the following code.
- (void)viewDidLoad
{
//The array of questions
NSMutableArray *questionArray = [[NSMutableArray alloc] initWithObjects:
[NSMutableArray arrayWithObjects:#"First Question",#"Answer A", nil],
[NSMutableArray arrayWithObjects:#"Second Quesiton",#"AnswerA",#"AnswerB", nil],
nil];
//remove used question from array
for (int i = questionArray.count; i>=0; --i) {
_questions = [questionArray objectAtIndex:arc4random() % questionArray.count];
[questionArray exchangeObjectAtIndex:i withObjectAtIndex:_questions];
}
//use array object
self.lblQuestion.text = [_questions objectAtIndex:0];
[self.btnA setTitle:[_questions objectAtIndex:1] forState:UIControlStateNormal];
[super viewDidLoad];
}
I'm getting the following warning:
Incompatible pointer to integer conversion sending NSMutableArray*_strong to parameter of type 'NSUInteger'
I take it this means I shouldn't be using another array to store the random question as I can't use this to remove the question from the array. However I don't know how else to do this?
Am I completely misunderstanding how I should go about this?
Since your goal here is to get non-repeating questions...
I believe that instead of removing the question you have already used, you should SHUFFLE your array at the beginning and then loop through the array one index at a time using a simple counter.
I hope you can find this piece of code helpful -- give it a shot:
-(NSMutableArray *)shuffleArray:(NSMutableArray *)anArray
NSUInteger count = [anArray count];
for (NSUInteger i = 0; i < count; ++i)
{
int nElements = count - i;
int n = (arc4random() % nElements) + i;
[anArray exchangeObjectAtIndex:i withObjectAtIndex:n];
}
return anArray;
}
-(void)viewDidLoad
{
//The array of questions
NSMutableArray *questionArray = [[NSMutableArray alloc] initWithObjects:
[NSMutableArray arrayWithObjects:#"First Question",#"Answer A", nil],
[NSMutableArray arrayWithObjects:#"Second Quesiton",#"AnswerA",#"AnswerB", nil],
nil];
//Shuffle the question array -- Now all indexes are shuffled and Random
questionArray = [self shuffleArray:questionArray];
//Every time you want to move to the next question, all you have to do is connect a button to the nextIndex action and let it do all the work!
//Use the nextIndex method to initialise -- we call it manually the first time so things would get going and something is displayed -- you can remove the line below if you want it to initialise on first button click! Your call the shots sir!
[self nextIndex];
[super viewDidLoad];
}
//Edit -- This method shows how to change question array index using a method
int currentIndex = 0;
-(IBAction)nextIndex
{
if ( currentIndex == [questionArray count] )
{
currentIndex = 0; //Resets the var when getting to the final Index
//The above line will result in a question loop -- meaning if you arrive at the last question, the next question will be the first! Pacman mode!
//If you want to stop at the last question just change the above line to return; and you're all set!
}
//Set _questions object to the current Index Array element
_questions = [questionArray objectAtIndex:currentIndex];
//Increment currentIndex for next use
currentIndex++;
//use the array object to set your objects' values
self.lblQuestion.text = [_questions objectAtIndex:0];
[self.btnA setTitle:[_questions objectAtIndex:1] forState:UIControlStateNormal];
}
You will end up having totally different questions that are shuffled every time.
I hope you find this helpful.

Issues using NSNumberFormatter?

I'm trying to make a label to show the temperature, with a maximum of 3 digits for temperatures over a 100, but I don't want any decimals...
NSString *longtempstring = [tmp description];
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setMaximumFractionDigits:3];
[formatter setMinimumFractionDigits:0];
NSString *shorttempstring = [formatter stringForObjectValue:[NSString stringWithString:longtempstring]];
The code above always returns (null)
Any ideas?
You are getting nil because the object you are passing to stringForObjectValue: is not of the type expected.
First of all, don't use stringForObjectValue:. That is a member of the parent class, NSFormatter. NSNumberFormatter has more specific methods that avoid confusion of object types like numberFromString: and stringFromNumber:.
Second, NSNumberFormatter is used to go from number to formatted string or formatted string to number. Not directly from formatted string to formatted string. You will need to use one number formatter to read your original string and produce a number and another to produce a new shorter formatted string from that number.
Of course, you might be able to make the first step (from long string to number) easier by using NSScanner or by taking a substring of your long string (cutting out everything except for the number itself) and then using the NSString method integerValue or doubleValue. A regular expression could also be used to extract the number from the first (longer) string.
The long and short of it is, this is a two step process. The first step (getting a number) can be accomplished any number of ways and a NSNumberFormatter might not be the easiest way. The second step (getting a new shorter string) is what NSNumberFormatter is perfect for.
I fixed it by converting the NSString to an NSNumber and only pulling the integer value from the string, thus removing any decimals.
NSString *longtempstring = [tmp description];
NSNumber *tempintegervalue = [NSNumber numberWithInteger:[longtempstring integerValue]];
NSString *shorttempstring = [tempintegervalue stringValue];
NSString *longtempstring = [tmp description];
What is the value of longtempstring here? Is it even a number?
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setMaximumFractionDigits:3];
[formatter setMinimumFractionDigits:0];
Why do you set maximum fraction digits to 3 if you say that you don't want any fraction digits? Fraction digits are what is "after the dot" and you say you don't want any decimals. If you don't want any decimals, minimum and maximum must be set to 0.
NSString *shorttempstring = [formatter stringForObjectValue:[NSString stringWithString:longtempstring]];
First of all, why are you copying the string? [NSString stringWithString:...] creates a new string that is a copy of the string you provide as argument. Strings are immutable, there is no need to copy them, they won't be modified. If you are afraid that a NSString may in fact be a NSMutableString, after all that is a subclass of NSString and you want to copy it, just copy it by calling [aString copy]. copy is a very smart method here. If the NSString is in fact a mutable string, it will really copy it, so you get an immutable copy. If it is not a mutable string, though, copy just returns the same string with a retain count increased by one (so in that case copy behaves exactly like retain). However, in your case copying makes no sense whatsoever.
And second, what makes you believe, that you can feed a string into a NSNumberFormater? It is called NSNumberFormater because it formats objects of type NSNumber. How is a NSString a NSNumber? It is not called NSStringFormater. If you feed an object of the wrong class to a formater, it will return nil, that's how this method is documented.
If your longtempstring contains a number with fraction, e.g. 12.345, then the correct code would look like this:
NSString * longtempstring = [tmp description];
NSNumberFormatter * formatter = [[NSNumberFormatter alloc] init];
[formatter setMaximumFractionDigits:0];
[formatter setMinimumFractionDigits:0];
NSNumber * tempnumber = [NSNumber numberWithDouble:[longtempstring doubleValue]];
NSString * shorttempstring = [formatter stringForObjectValue:tempnumber];
However, if all you want to do is cut off the decimals, that is a horrible way to do it. This can be done much more effective:
double d;
NSString * longtempstring;
NSString * shorttempstring;
longtempstring = #"12.345";
d = [longtempstring doubleValue];
shorttempstring = [NSString stringWithFormat:#"%d", (int)d];
This is much shorter, needs less memory, and is at least three times faster. If you want to round the number (that means everything with a fraction .5 and above is rounded to the next higher value), just round it:
d = round([longtempstring doubleValue]);

Check for String within a String

I'm trying to compare two strings
NSString strOne = #"Cat, Dog, Cow";
NSString strTwo = #"Cow";
How do I determine if strOne contains strTwo
Try using rangeOfString:
NSRange result = [strOne rangeOfString:strTwo];
From the documentation:
Returns an NSRange structure giving the location and length in the receiver of the first occurrence of aString. Returns {NSNotFound, 0} if aString is not found or is empty (#"").
For anyone needing the code to check is a string exists within a string, here's my code thanks to fbrereto. This example checks to see if any string contained in an array of strings (stringArray) can be found within a string (myString):
int count = [stringArray count];
for (NSUInteger x = 0; x < count; ++x) {
NSRange range = [self.myString rangeOfString:[stringArray objectAtIndex:x]];
if (range.length > 0) {
// A match has been found
NSLog(#"string match: %#",[stringArray objectAtIndex:x]);
}
}
I believe this is the correct syntax for checking if the range exists (correcting response from Kendall):
range.location != NSNotFound
Gradually straying off topic, but I always explode my strings, which would mean just exploding it using your search string as a key and you can use the array count to see how many instances you have.
Just incase anyone is coming from a code language that uses "explode" to blow a string up into an array like me, I found writing my own explode function tremendously helpful, those not using "explode" are missing out:
- (NSMutableArray *) explodeString : (NSString *)myString key:(NSString*) myKey
{
NSMutableArray *myArray = [[NSMutableArray alloc] init];
NSRange nextBreak = [myString rangeOfString:myKey];
while(nextBreak.location != NSNotFound)
{
[myArray addObject: [myString substringToIndex:nextBreak.location]];
myString = [myString substringFromIndex:nextBreak.location + nextBreak.length];
nextBreak = [myString rangeOfString:myKey];
}
if(myString.length > 0)
[myArray addObject:myString];
return myArray;
}
works like this:
[self explodeString: #"John Smith|Age: 37|Account Balance: $75.00" key:#"|"];
which will return this array:
[#"John Smith", #"Age: 37", #"Account Balance: $75.00"];
This lets you quickly pull out a specific value in a tight space, Like if you have a client and you want to know how much money he has:
[[self explodeString: clientData key: pipe] objectAtIndex: 1];
or if you wanted specifically the dollar amount as a float:
[[[self explodeString: [[self explodeString: clientData key: pipe] objectAtIndex: 1] key: #": "] objectAtIndex: 2] floatValue];
anyway I find arrays way easier to work with and more flexible, so this is very helpful to me. Additionally with a little effort you could make an "explodable string" data type for your private library that lets you treat it like a string or return an index value based on the key
ExplodableString *myExplodableString;
myExplodableString.string = #"This is an explodable|string";
NSString *secondValue = [myExplodableString useKey: #"|" toGetValue: index];

Resources