iOS thread error when reading from a text file - ios

I'm trying to print an individual element of an array from a text file, here is the code I'm using :
//Tells the compiler where the text file is and its type
NSString* path = [[NSBundle mainBundle] pathForResource:#"shakes"
ofType:#"txt"];
//This string stores the actual content of the file
NSString* content = [NSString stringWithContentsOfFile:path
encoding:NSUTF8StringEncoding
error:NULL];
//This array holds each word separated by a space as an element
NSArray *array = [content componentsSeparatedByString:#" "];
//Fast enumeration for loop tha prints out the whole file word by word
// for (NSString* word in array) NSLog(#"%#",word);
//To access a certain element in an array
NSLog(#"%#", [array objectAtIndex:3
]);
The problem is - if I wish to access the first 2 elements, 0 or 1, that is fine. However, as soon as I wish to access say, element 2 or 3 I get the following error :
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 3 beyond bounds [0 .. 1]
It is a SIGABRT threading error - something which seems to crop a lot in iOS programming, but it's normally quite solvable.
The text file "Shakes.txt" is 6 elements long and is only really for testing purposes.
PS - The third line is commented out just incase I want to use it later... So don't worry about that.
Thanks in advance for any help!

Basically you are trying to access an object which is out of bounds of the array.
The log is very obvious your array only has 1 element and you are trying to access the 4th one.
Add this to your code.
NSMutableArray *contentArray = [[NSMutableArray alloc] init];
for (NSString* word in array)
{
[contentArray addObject:word]
}
//Now try to access contentArray
NSLog(#"%#", [contentArray objectAtIndex:3
]);

Related

IOS NSDictionary element to NSString

Hi I am trying to extract key value from NSDictionary, the dictionary value looks like below screen shot
I need to extract the value with key "TITLE" to NSString, using the code
NSDictionary* tmp = [self getDBRequest:req];
NSString * title =[tmp valueForKey:#"TITLE"];
But giving the the value like
Is there anything wrong with above code?
Edit:
NSLog(#"%#", tmp);
Gives the output
2015-12-31 11:04:52.530 SimpleTable[610:10059] (
{
DESCRIPTION = "30% OFF ON NEW ";
"IMAGE_URL" = "crowd.jpg";
TITLE = "GET 30% OFF";
}
)
Edit2
Actualy using the result of NSString * title =[tmp valueForKey:#"TITLE"]; I have to replace an element of NSMutableArray
And the code
NSMutableArray *array = [[NSMutableArray alloc]init];
[array addObject:#"Eezy"];
[array addObject:#"Tutorials"];
NSDictionary* tmp = [self getDBRequest:req];
NSString * title =[tmp valueForKey:#"TITLE"];
[array replaceObjectAtIndex:0 withObject:title];
Giving me the array modified some thing like below screen shot
Look at the first image in your question, the first line of the contents dump says "1 object".
Also look at the output of the NSLog, notice the parentheses (( & )) which surround the braces ({ & }), which in turn surround the key/value pairs.
Both these are telling you that tmp is not referencing an NSDictionary as you think, but an NSArray containing a single element and that element is an NSDictionary.
Now when you invoke valueForKey: on an array of dictionaries it does the key lookup on every dictionary in the collection and returns and array of results.
Which is why when you look at the second image in your question you see that its contents dump also starts with "1 object" - title is referencing an array containing one element, being your string.
This is also why, as mentioned in the comments, that using objectForKey: in place of valueForKey: causes an error - that method does not operate on arrays and so produces the unrecognized selector sent to instance error.
HTH
try like bellow code.
NSDictionary *tmp = #{#"DESCRIPTION" : #"30 OFF ON NEW",#"IMAGE_URL" : #"crowd.jpg",#"TITLE" : #"GET 30% OFF"};
//NSDictionary* tmp = [self getDBRequest:req];
NSArray *keyArray = [tmp allKeys];
NSString * title = [keyArray objectAtIndex:[keyArray indexOfObject:#"TITLE"]];//[keyArray objectAtIndex:0];
[array replaceObjectAtIndex:0 withObject:title];

ios - get values from NSDictionary

I have JSON on my server, which is parsed into iOS app to NSDictionary. NSDictionary looks like this:
(
{
text = Aaa;
title = 1;
},
{
text = Bbb;
title = 2;
}
)
My question is - how to get just text from first dimension, so it should be "Aaa". I've tried to use this:
[[[json allValues]objectAtIndex:0]objectAtIndex:0];
But it didn't work, it ends with error
Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '-[__NSCFArray allValues]:
unrecognized selector sent to instance 0x714a050'
So can you help me please, how to get just one value from specified index? Thanks!
That error message is simply telling you that NSDictionary (which is the first object of that array, along with the second) doesn't respond to objectAtIndex.
This will be a bit cody, but it explains it better:
NSArray *jsonArray = [json allValues];
NSDictionary *firstObjectDict = [jsonArray objectAtIndex:0];
NSString *myValue = [firstObjectDict valueForKey:#"text"];
Your JSON object is an array, containing two dictionaries. That's how to get the values:
NSDictionary* dict1= json[0];
NSString* text= dict1[#"text"];
NSString* title= dict1[#"title"];
Try this:
NSString *txt = [[json objectAtIndex:0] objectForKey:#"text"];
UPDATE: Have fixed the error. Thanks yunas.

NSLog string is fine but string into UITextView causes exception [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
So I have a view controller and in the viewdidload method it's supposed to load some content from a webpage (just a proof of concept, it'll be cached eventually). It gets the content using the tfhipple library and puts the contents into an array, it logs the data to the console and then I want it to apply the contents to a UITextView. However when the view controller is called it gets so far as to log the text to the console but on the line where it sets it as the contents of the UITextView it causes an exception.
NSData *dataURL;
NSString *url = #"http://www.testwebsite.com/testpage.html";
dataURL = [NSData dataWithContentsOfURL: [NSURL URLWithString: url]];
NSString *serverOutput = [[NSString alloc] initWithData:dataURL encoding: NSASCIIStringEncoding];
TFHpple * doc = [[TFHpple alloc] initWithHTMLData:dataURL];
NSArray *elements = [doc searchWithXPathQuery:#"//div[contains(#id,'main-section')]//text()"];
NSString * aboutcontents = [elements objectAtIndex:2];
NSLog(#"test: %#", aboutcontents);
self.aboutbox.text = aboutcontents;
The exception it causes is as follows, along with the console output before hand:
2013-06-24 09:37:51.433 AppName[24765:c07] test: {
nodeContent = "Test Content";
nodeName = text;
raw = "Test Content";
}
2013-06-24 09:37:51.434 AppName[24765:c07] -[TFHppleElement length]: unrecognized selector sent to instance 0x8043be0
2013-06-24 09:37:51.434 AppName[24765:c07] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[TFHppleElement length]: unrecognized selector sent to instance 0x8043be0'
*** First throw call stack:
(0x25d012 0x16ebe7e 0x2e84bd 0x24cbbc 0x24c94e 0x76b4fb 0x3347 0x7111c7 0x711232 0x7328c9 0x732704 0x730bda 0x730a5c 0x732647 0x16ff705 0x6332c0 0x633258 0x855ff4 0x16ff705 0x6332c0 0x633258 0x6f4021 0x6f457f 0x6f4056 0x859af9 0x16ff705 0x6332c0 0x633258 0x6f4021 0x6f457f 0x6f36e8 0x662cef 0x662f02 0x640d4a 0x632698 0x22b2df9 0x22b2ad0 0x1d2bf5 0x1d2962 0x203bb6 0x202f44 0x202e1b 0x22b17e3 0x22b1668 0x62fffc 0x2fdd 0x21a5)
libc++abi.dylib: terminate called throwing an exception
(lldb)
I'm a little bit stuck as to why it does this. If I manually set the string aboutcontents to something then it changes the contents of the UITextView without issue.
Any help is as always appreciated.
Try this:
TFHppleElement * aboutcontents = [elements objectAtIndex:2];
NSLog(#"test: %#", [aboutcontents text]);
self.aboutbox.text = [aboutcontents text];
Here is the documentation part taken from hpple:
TFHppleElement * element = [elements objectAtIndex:0];
[e text]; // The text inside the HTML element (the content of the first text node)
[e tagName]; // "a"
[e attributes]; // NSDictionary of href, class, id, etc.
[e objectForKey:#"href"]; // Easy access to single attribute
[e firstChildWithTagName:#"b"]; // The first "b" child node
Try to get attributes for example and see what it returns to you.
you getting resutt for NSString * aboutcontents = [elements objectAtIndex:2]; is a dictionary,convert dictionary into string like this
NSString * aboutcontents=[NSString stringWithFormat:#"%#",[elements objectAtIndex:2]];
Try this.
NSDictionary * aboutcontents = [elements objectAtIndex:2];
NSLog(#"test: %#", aboutcontents);
self.aboutbox.text = [aboutcontents objectForKey:#"nodeContent"];
I don't understand the context but I saw { } in the Log and I guess only dictionaries get printed that way.

Modifying NSDictionary in run Time [duplicate]

This question already has answers here:
Mutable Objects inside NSUserDefaults
(4 answers)
Closed 9 years ago.
Please Help me.
I have a plist clothingList.plist
I am accessing it like this in a method
NSString *path=[[NSBundle mainBundle] pathForResource:#"ClothingList" ofType:#"plist"];
//NSDictionary *ClothingAssets ; //Declared globally in .h file
ClothingAssets=[[NSMutableDictionary alloc]initWithContentsOfFile:path];
[[NSUserDefaults standardUserDefaults]setObject:ClothingAssets forKey:#"ClothingAssets"];
[[NSUserDefaults standardUserDefaults] synchronize];
Now I want to modfify a bool value in Clothing Assets Dictionary in another method.
ClothingAssets=[[NSUserDefaults standardUserDefaults] dictionaryForKey:#"ClothingAssets"];
[[[[[[ClothingAssets objectForKey:#"ClothingStore"] objectAtIndex:temp_Store]objectForKey:#"Assets" ]objectForKey:[NSString stringWithFormat:#"%#",temp_AssetType]] objectAtIndex:ii] setValue:#"YES" forKey:#"isLock"] ;
When I run the code For the first time it crashes and Show an error like this:
************ Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFDictionary setObject:forKey:]: mutating method sent to immutable object'***
*** First throw call stack:
(0x1fb5012 0x29c5e7e 0x1fb4deb 0x1f7b347 0x3f39bf 0x435d9 0x41f76 0xea5020 0x29d9705 0xab5920 0xab58b8 0xb76671 0xb76bcf 0xb75d38 0xae533f 0xae5552 0xac33aa 0xab4cf8 0x3397df9 0x3397ad0 0x1f2abf5 0x1f2a962 0x1f5bbb6 0x1f5af44 0x1f5ae1b 0x33967e3 0x3396668 0xab265c 0x22ed 0x2225 0x1)
libc++abi.dylib: terminate called throwing an exception******
But When I run the code for second time it is working properly.
please help me.
There are many similar questions. From the exception its evident that you are trying to include a value to an immutable dictionary.
Unwrap the values one at a time and since you are going to edit them always make a mutableCopy
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableDictionary *clothingAssets=[[defaults dictionaryForKey:#"ClothingAssets"] mutableCopy];
NSMutableArray *clothingStores = [clothingAssets[#"ClothingStore"] mutableCopy];
NSMutableDictionary *clothingStore = [clothingStores[temp_Store] mutableCopy];
NSMutableDictionary *assets = [clothingStore[#"Assets"]mutableCopy];
NSString *assetTypesKey = [NSString stringWithFormat:#"%#",temp_AssetType];
NSMutableArray *assetTypes = [assets[assetTypesKey]mutableCopy];
NSMutableDictionary *assetType = [assetTypes[i] mutableCopy];
//Value is set
assetType[#"isLock"] = #"YES";
//Now you need to update the values back to the top most level
[assetTypes replaceObjectAtIndex:i withObject:assetType];
assets[assetTypesKey] = assetTypes ;
clothingStore[#"Assets"] = assets;
[clothingStores replaceObjectAtIndex:temp_Store withObject:clothingStore];
clothingAssets[#"ClothingStore"] = clothingStores;
[defaults setObject:clothingAssets forKey:#"ClothingAssets"];
[defaults synchronize];
Nested message sends aside, this is actually rather straightforward. When you see that error, it means you're trying to mutate an immutable object. The runtime throws a tantrum when you try to do that. Instead, do this:
ClothingAssets=[[NSUserDefaults standardUserDefaults] dictionaryForKey:#"ClothingAssets"];
NSDictionary *clothingStore = [ClothingAssets objectForKey:#"ClothingStore"];
NSArray *assets = [clothingStore objectForKey:#"Assets"];
NSDictionary *subAsset = [assets objectAtIndex: temp_Store];
NSArray *subAssetArray = [subAsset objectForKey: [NSString stringWithFormat:#"%#",temp_AssetType];
// At this point I'm afraid I run out of creative ways to describe your storage hierarchy:
NSDictionary *subAssetArraySubDictionary = [subAssetArray objectAtIndex: ii];
NSMutableDictionary *mutableCopy = [subAssetArraySubDictionary mutableCopy];
// And finally, set the value:
// Beware: This uses the string YES instead of a boolean value for YES - you need to remember this
// when accessing it later.
[mutableCopy setValue: #"YES" forKey: #"isLock"];

Fast Enumeration error?

Getting a warning saying that:
Collection expression type 'NSString *' may not respond to 'countByEnumeratingWithState:objects:count'
when trying to run the following code:
NSString *proper = [NSString stringWithContentsOfFile:#"usr/share/dict/propernames" encoding:NSUTF8StringEncoding error:NULL];
for (NSString *i in proper){
NSLog(#"Item>%#", i);
}
When I run the program I don't get any output from the NSLog statement. Anyone run into this?
The compiler warning is trying to tell you that you cannot iterate over an NSString using a for ... in ... loop. It is further trying to say than the reason for this is that an NSString is not a valid "Collection" type. Your valid "Collection" types are things like NSArray, NSSet, and NSDictionary.
So if your file is supposed to contain structured data, you should parse it into something more useful than a flat NSString. Something like this may give a better result:
NSString* temp = [NSString stringWithContentsOfFile:#"usr/share/dict/propernames" encoding:NSUTF8StringEncoding error:NULL];
NSArray* proper = [temp componentsSeparatedByString:#"\n"];
for (NSString* i in proper){
NSLog(#"Item>%#", i);
}
That will print each line in the file. This assumes, of course, that your input file has one entry per line. If it is structured some other way, then you will have to parse it differently.
After you load the file, split it into lines with componentsSeparatedByString: .
NSArray *lines = [proper componentsSeparatedByString:#"\n"]; // Use the correct line ending character here
for (NSString *i in lines) {
NSLog(#"item> %#", i);
}
This is a clear mistake u have here.
NSString* is a string object and is not a collection of characters as the string object known in C++ which is a character array.
for-in Loop need a collection to iterate within. like NSArray or NSSet.

Resources