I'm doing some work using the RedPark Serial Cable for iOS. This is a cable that allows serial communication between an iOS device and another device like a microcontroller.
There is a method that comes with the RedPark SDK that reads the bytes available on the Serial Line. This method is called anytime the cable receives informatino.
(void)readDataBytes(UInt32 bytes) {
NSString *s = [[NSString alloc] initWith...bytes];
NSString *editedString = [self extractSubStringMethod:s];
[myArray addObject:editedString];
}
The microcontroller is sending the information in the following format
<msg>xxxxxxxxxxxxx</msg>
I want to be able to extract the x's from the message (which is taken in as an NSString). At the moment I'm using NSRange to extract everything after position 4 (the first x) and before the final "< /msg>" I'm not convinced it works and was wondering is there any other ideas?
Finally, I have an NSThread which is running alongside this, I have the messages being added to an NSMutableArray. So what I want is, the NSThread to be manipulating/displaying the message information when there is a message received from the cable. I have something like the following
//Thread method,
while([myArray count] > 0) //Don't believe this is neccesary but its in anyway
{
for(int i = 0; i < [myArray count]; i++){
NSString *string = [myArray objectAt(i)];
[self displayString:string];
[myArray removeObjectAt(i);
}
}
I believe it's crashing around the above... [self displayString:string] just sets the value of a label, something like
-(void)displayString(NSString *string) {
label.text = [string charAt(1)];
}
The code above is just from memory as I've left my Mac at home and I'm in work.
Any suggestions/help would be appreciated
Instead of
while([myArray count] > 0) //Don't believe this is neccesary but its in anyway
{
for(int i = 0; i < [myArray count]; i++){
NSString *string = [myArray objectAt(i)];
[self displayString:string];
[myArray removeObjectAt(i);
}
}
try like this:
while ([myArray count] > 0)
{
[self displayString: myArray[0]];
[myArray removeObjectAtIndex: 0];
}
To address your first concern, [string substringWithRange:NSMakeRange(5, string.length - 6)] should be sufficient and should work without any issues. You could use an NSRegularExpression to match the content inside the tags, but that would be overkill for such a simple task (and would have a performance hit).
Secondly, UIKit methods must only be called from the main thread (see documentation):
Note: For the most part, UIKit classes should be used only from an application’s main thread. This is particularly true for classes derived from UIResponder or that involve manipulating your application’s user interface in any way.
You appear to be setting the text of a label in a different thread. This is what is causing the crash. You need to call your displayString: method like this:
[self performSelectorOnMainThread:#selector(displayString:) withObject:string waitUntilDone:YES];
This will execute the method on the main thread instead of on a background thread.
You must not update UI on secondary thread.
Mutable classes are not thread safe.
while([myArray count]){
NSString *string = [myArray objectAt(0)];
[self performSelectorOnMainThread:#selector(displayString:) withObject:string waitUntilDone:NO];
[myArray removeObjectAt(0);
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I want to fetch data from my NSMutableArray, I am doing this
-(void)ViewDidLoad{
A_array = [[NSMutableArray alloc] init];
A_array = [NSMutableArray arrayWithObjects:#"4",#"6",#"2",#"3",#"0",#"5",#"1",#"2",#"4",#"1",#"0",#"2",#"4",#"2",#"0",#"3",nil]
var_Count_Answer_A = 0; // int
}
-(void)method_Second {
NSLog(#"%#",[A_array objectAtIndex:var_Count_Answer_A]); // This line is crashing if I click button again. First time line works fine but if we click button again and var_Count_Answer = 2 then it will crash.
NSString *str1 = [[NSString alloc]initWithFormat:#"%#",[A_array objectAtIndex:var_Count_Answer_A]]; // If I comment on NSLOG then this line will crash
A = [str1 integerValue];
NSLog(#"A is %d",A);
var_Count_Answer_A ++;
}
if I try this NSLog(#"%#",[A_array objectAtIndex:5]); // works fine
NSLog(#"%#",[A_array objectAtIndex:var_Count_Answer_A]); // var_Count_Answer_A =5; and crash
Any Idea or Suggestions would be highly appreciated.
Your code hurt my eyes
There are certain coding standards to be followed while writing code in Objective-C. Every language got one. They make code readable and understandable. You can refer to Cocoa Coding Guidelines and help yourself writing better looking code.
Explain Properly
Without the error message before crash no one can help you. Next time when you post about a crash, also explain the error message you got.
Was it a EXEC_BAD_ACCESS? If so it is the awesome garbage collector sweeping your array object away. Anyway your code sores my eyes and I am taking the privilege refactoring the code. Maybe it will help you.
A little bit of refactoring
NSArray *aArray;
- (void)viewDidLoad
{
[super viewDidLoad];
aArray = #[#"1", #"2", #"3", #"4"];
// or use[[NSArray alloc]initWithObjects:#"1", #"2", #"3", #"4", #"5"];
//Why do you need a mutable array while initializing it static?
}
- (void)methodSecond
{
static int counter = 0;
if (aArray) {
if (counter<aArray.count) {
NSLog(#"A is %u",[[aArray objectAtIndex:counter++]integerValue]);
} else {
counter = 0;
[self methodSecond];
}
}
}
Understand what you are doing
So a detail explanation of what I guess your problem is:
You're using [NSArray initWithObjects:] this creates an autoreleased object, and we got no control over its life time. And they get released if they are not referenced immediately after creating, which is probably whats happening your case. In my experience, mutable autoreleased object always sources bad access problems. So it is better to have the object alloc and inited, ie.. [[NSArray alloc]initWithObjects:] and I observe you are not adding/removing array members in run-time. There is no purpose of having a MutableArray.
In your code, you're creating two objects. The first array object is allocated and immediately dereferenced in the next line. Which is probably a mistake.
If you want to know more about auto-released objects. Read this.
Use
A_array = [[NSMutableArray alloc] initWithObjects:#"4",#"6",#"2",#"3",#"0",#"5",#"1",#"2",#"4",#"1",#"0",#"2",#"4",#"2",#"0",#"3",nil];
Instead you used.
A_array = [[NSMutableArray alloc] init];
A_array = [NSMutableArray arrayWithObjects:#"4",#"6",#"2",#"3",#"0",#"5",#"1",#"2",#"4",#"1",#"0",#"2",#"4",#"2",#"0",#"3",nil];
As I review Your Project is ARC disable try this Working fine for me.
ViewControler.h
#interface MasterViewController : UIViewController
{
NSMutableArray *A_array;
int var_Count_Answer_A;
}
ViewControler.m
-(void)viewDidLoad {
[super viewDidLoad];
A_array = [[NSMutableArray alloc] initWithObjects:#"4",#"6",#"2",#"3",#"0",#"5",#"1",#"2",#"4",#"1",#"0",#"2",#"4",#"2",#"0",#"3",nil];
var_Count_Answer_A = 0;
var_Count_Answer_A = 0; // int
}
-(IBAction)method_Second:(id)sender {
NSLog(#"%#",[A_array objectAtIndex:var_Count_Answer_A]);
NSString *str1 = [[NSString alloc]initWithFormat:#"%#",[A_array objectAtIndex:var_Count_Answer_A]]; // If I comment on NSLOG then this line will crash
int A = [str1 integerValue];
NSLog(#"A is %d",A);
var_Count_Answer_A++;
}
But As Everyone know at last there must be occur this exception.
NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 16 beyond bounds [0 .. 15]'
As trying to access array index object that does not exist.
And if you still have some error then First Enable NSZombie in your project Follow this.
-> "Product" menu, select "Edit Scheme", go to the "YourAp.app" stage in the left panel, and the "Arguments" tab on the right. You can then add NSZombieEnabled to the "Environment Variables" section and set the value to YES.
And Now Share your Crash Log.
in your code you are usimng two different varaibles once check thosetwo.
var_Count_Answer and var_Count_Answer_A
This error occurs because you are using an auto-released object.
When you call like:
A_array = [NSMutableArray arrayWithObjects:#"4",#"6",#"2",#"3",#"0",#"5",#"1",#"2",#"4",#"1",#"0",#"2",#"4",#"2",#"0",#"3",nil]
The A_array is an autoreleased object, you can't say when it'll be released. That is why this error occurs.
Solution:
Declare a property for the array like:
#property (nonatomic, strong) NSMutableArray *A_array;
Then modify your methods like:
-(void)ViewDidLoad
{
_A_array = [NSMutableArray arrayWithObjects:#"4",#"6",#"2",#"3",#"0",#"5",#"1",#"2",#"4",#"1",#"0",#"2",#"4",#"2",#"0",#"3",nil]
var_Count_Answer_A = 0; // int
}
-(void)method_Second
{
NSLog(#"%#",[_A_array objectAtIndex:var_Count_Answer_A])
NSString *str1 = [[NSString alloc]initWithFormat:#"%#",[_A_array objectAtIndex:var_Count_Answer_A]];
A = [str1 integerValue];
NSLog(#"A is %d",A);
var_Count_Answer_A ++;
}
I know there are many questions about this topic but non of them work for me because mine is a little weird.
First of all I create a static singleton class. and declare a variable of NSMutableDictionary
static NSMutableDictionary* mydic
#implementation mySingleton
-(mySingleton*)getInstance
{
static mySingleton *sharedInstance;
#synchronized(self)
{
if(!sharedInstance)
{
sharedInstance = [[mySingleton alloc] init];
mydic = [[NSMutableDictionary alloc] initWithCapacity:1];
}
return sharedInstance;
}
}
-(NSMutableDictionary*)getDictionary
{
return myDic;
}
then I call this NSMutableDictionary from another class like the below.
NSMutableDictionary* singletonDictionary = [[mySingleton getInstance] getDictionary];
MyOtherClass* myclass = [singletonDictionary objectForKey:key];// Key is NSString
// Here I can see whole the values I added to myClass for that key
NSArray *checkKey = [singletonDictionary allKeys];
for(int i = 0; i < [singletonDictionary count]; i++)
{
NSLog(#"%#",[checkKey objectAtIndex:i]);// here I can see my key is there
}
[singletonDictionary removeObjectForKey:key];// here it crashes EXC_BAD_ACCESS
I am gonna get crazy about this problem. If someone has an idea please share it with me.
EDIT :
MyOtherClass * myinstance = [[MyOtherClass alloc] init];
// Fill up the instance with the desired variable here
// Forexample
// myinstance.name = [NSString stringWithFormat:#"myInstanceName"];
.
.
.
[[[mySingleton getInstance] getDictionary] setObject:myinstance forKey:key]// key is an NSString*
[myinstance release];
Thanks for help.
Omer Faruk KURT
So many problems, where to start...?
At least, it seems your getInstance method is not returning anything; it should probably return mySingleton. This could explain your EXEC_BAD_ACCESS, as singletonDictionary is probably nil as things stand.
Your singleton instantiation is wrong too - you need to check if the singleton has already been created, and return it if it has. Otherwise you can reallocate singletons, which is absurd.
Static references are poor design here, better to subclass and declare members in the header file.
This might fix your problems, but you're clearly jumping in at the deep end and you're going to encounter more trouble. I think you need to find good examples of code in texts or online and study those. If you do that pretty soon you'll learn the ropes.
The NSMutableDictionary retains objects added to the dictionary. When the objects are removed they are released. As a result, removing an object from the dictionary accesses the object. If you have previously released the object and it is dealloc'ed, then this can cause an exception to be raised. If you examine the state of the object prior to removing from the dictionary you will likely see that it has already been released and dealloced.
I am just learning objective-c and iPhone development, and I am really struggling with some very basic tasks. I am only on my 3rd day of the learning process - so that is to be expected somewhat. I'm still almost ashamed to ask such a simple question.
Anyhow, here's my question. I have a .NET web service which I call using a GET for http://somehost/ping
it returns 'pong'
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">pong</string>
The simplest of test cases.
Back on the iPhone when I retrieve the URL I have the above string as a result. I only want the 'pong' part. This seems like programming 101, but I can't seem to find a simple example of how to do it that doesn't involve defining delagates or other seemingly complex processing steps.
The problem is simple enough, find the first '>' and extract everything from there until the first '<' as an NSString. That's all I need to do.
Does anyone have a basic example of how to do this?
This is dry-coded, and kinda ugly imho. But here is a more direct answer.
NSString *xml = #"<tag>pong</tag>";
NSRange range = [xml rangeOfString:#">"];
xml = [xml substringFromIndex:range.location + 1];
range = [substring rangeOfString:#"<"];
xml = [xml substringToIndex:range.location];
Hey Sylvanaar, I'm having to do similar types of parsing inside of the client. My general methodolgy for parsing xml responses is like this. I'm pretty sure the classes are available on iphone side too. Note: it may not be the absolute best method, but it does work.
- (id)initWithXMLNode:(NSXMLNode *)node {
self = [super init];
if (self != nil) {
NSError *error;
NSArray *objects;
// Get the fingerprint
objects = [node objectsForXQuery:#"for $fingerprint in ./Fingerprint return data($fingerprint)" error:&error];
handleErrorInInit(error)
fingerprint = getFingerprint(objects);
// Get the moduleName
objects = [node objectsForXQuery:#"for $moduleName in ./Foldername return data($moduleName)" error:&error];
handleErrorInInit(error)
moduleName = getNSString(objects);
}
return self;
}
Worth showing this too. Note that NSXMLDocuments are a subclass of NSXMLNodes.
- (NSXMLDocument *)xmlDocumentFromData:(NSData *)data {
NSError *error;
NSXMLDocument *document = [[[NSXMLDocument alloc] initWithData:data options:0 error:&error] autorelease];
if (error) {
[NSApp presentError:error];
return nil;
}
return document;
}
Sometimes a full on XML parse makes sense, but a quick index/substring routine can be appropriate as well:
NSRange startBracket = [xmlFragment rangeOfString:#">"];
if(startBracket.location != NSNotFound) {
NSRange endBracket = [xmlFragment rangeOfString:#"<"
options:0
range:NSMakeRange(startBracket.location,
[xmlFragment length] - startBracket.location)];
if(endBracket.location != NSNotFound) {
NSString *value = [[xmlFragment substringFromIndex:startBracket.location+1]
substringToIndex:endBracket.location];
// Do something with value...
}
}
(Not tested, needs more error handling, yadda yadda yadda..)
Update: I edited the code, but the problem persists...
Hi everyone,
this is my first post here - I found this place a great ressource for solving many of my questions. Normally I try my best to fix anything on my own but this time I really have no idea what goes wrong, so I hope someone can help me out.
I am building an iPhone app that parses a couple of xml files using TouchXML. I have a class XMLParser, which takes care of downloading and parsing the results. I am getting memory leaks when I parse an xml file more than once with the same instance of XMLParser.
Here is one of the parsing snippets (just the relevant part):
for(int counter = 0; counter < [item childCount]; counter++) {
CXMLNode *child = [item childAtIndex:counter];
if([[child name] isEqualToString:#"PRODUCT"])
{
NSMutableDictionary *product = [[NSMutableDictionary alloc] init];
for(int j = 0; j < [child childCount]; j++) {
CXMLNode *grandchild = [child childAtIndex:j];
if([[grandchild stringValue] length] > 1) {
NSString *trimmedString = [[grandchild stringValue] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
[product setObject:trimmedString forKey:[grandchild name]];
}
}
// Add product to current category array
switch (categoryId) {
case 0:
[self.mobil addObject: product];
break;
case 1:
[self.allgemein addObject: product];
break;
case 2:
[self.besitzeIch addObject: product];
break;
case 3:
[self.willIch addObject: product];
break;
default:
break;
}
[product release];
}
}
The first time, I parse the xml no leak shows up in instruments, the next time I do so, I got a lot of leaks (NSCFString / NSCFDictionary).
Instruments points me to this part inside CXMLNode.m, when I dig into a leaked object:
theStringValue = [NSString stringWithUTF8String:(const char *)theXMLString];
if ( _node->type != CXMLTextKind )
xmlFree(theXMLString);
}
return(theStringValue);
I really spent a long time and tried multiple approaches to fix this, but to no avail so far, maybe I am missing something essential?
Any help is highly appreciated, thank you!
The issue is likely in this line:
[self.mobil addObject:[product copy]];
By calling for a copy of product you're creating a new NSMutableDictionary instance with a retain count of 1. The mobil instance, however, will increment the copy's retain count when you send it the addObject: message, so the retain count of the copy is now 2. Generally speaking, an object is responsible for handling its own object memory, so any time you message setFoo: or addObject:, you can just pass the object directly, even if its autoreleased or you are planning to release it right after the call; it is the receiver's responsibility to retain the object you're passing if it needs to hold onto it.
Because you did not assign the copy to any variable, you do not have a pointer that you can use to decrement the copy's retain count now that you're no longer interested in it, so even if mobil releases the product copy at some point, the copy will never reach a retain count of 0. Your [product release] statement at the end of the for loop releases the original product object, not the copy you created.
Instead, try the following and see if instruments is happier:
[self.mobil addObject:product];
In simple terms, every time you use copy, you also have to use release/autorelease somewhere.
And in this instance, the even easier answer is to not use copy in the first place, since you aren't doing anything with the original version of product after you've copied it.
I fixed the problem myself. It was kind of stupid, but maybe someone might come across the same thing, so I am going to post it here.
1) I had mutable array set up as instance variables like this:
#interface XMLParser : NSObject {
// ...
NSMutableArray *mobil;
// ...
}
#property(nonatomic, retain) NSMutableArray *mobil;
#end
Everytime I wanted to restore new data inside I did:
self.mobil = nil;
Which did not what I wanted to do, so this is the better approach:
[self.mobil removeAllObjects];
2) The dealloc method has to be like this to fix the leaks (because mobil is defined as a property):
-(void)dealloc {
[mobil release];
self.mobil = nil;
}
Whew, that has been a lot of work to find out - hope it saves someone else some time :-)