I am going to quickly cut to the chase here, I am using the MailCore API to connect to email and download messages into an array, then take those messages in the array and display them into a Table View.
Here is the code (retrieved from official MailCore website) that will download ALL the messages off of the server:
messageSet = [inbox messagesFromUID:1 to:0 withFetchAttributes:CTFetchAttrEnvelope];
Basically, this will download all the messages from the server and I can confirm this by reporting the contents of the Array with an NSLog, all the messages are there.
Here is now the code that will take ONLY THE FIRST MESSAGE (index 0) and add that to my messages array:
CTCoreMessage *msg = [messageSet objectAtIndex:0];
BOOL isHTML;
isHTML = YES;
messages = [[NSMutableArray alloc] init];
sendernames = [[NSMutableArray alloc] init];
[messages addObject:[msg bodyPreferringPlainText:&isHTML]];
NSString *sender = [NSString stringWithFormat:#"%#", [msg sender]];
[sendernames addObject:sender];
[tableView reloadData];
So again, this takes the message at index 0, which is the first message and adds it to the messages array. I also have code in there that gets the senders name and adds that to the sender array, ignore that.
Here is the code in my cellForRowAtIndexPath method (just a clipping of the values I am setting for my elements on the cell):
cell.nameText.text = [sendernames objectAtIndex:0];
cell.messageText.text = [messages objectAtIndex:0];
As you can see, it displays the index 0 object, the first message, the same one we added earlier.
Lastly, here is the code that sets how many rows I have. It is based on the messagesSet array which downloads ALL of the messages.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [messageSet count];
}
My question is, how can I modify my code to do two things:
1.) Add ALL the DOWNLOADED objects to the array and not just the first one.
2.) Modify the cellForRowAtIndexPath code to display all the objects in the messages array.
Thanks so much in advance!
Well firstly you iterate through the array and fill your array as so
for (CTCoreMessage *msg in messageSet) {
[messages addObject:[msg bodyPreferringPlainText:&isHTML]];
NSString *sender = [NSString stringWithFormat:#"%#", [msg sender]];
[sendernames addObject:sender];
}
Then in the cell for row just do what you were doing, but instead of passing 0 for object at index pass: indexPath.row
Hope this helps.
The model backing your table is really messageSet. You assign that with the result of the server call. Just use that in your delegate methods:
After the download, call [self.tableView reloadData];
numberOfRowsInSection: can return messageSet.count;
cellForRowAtIndexPath: will be called sequentially for each visible indexPath. It doesn't need to deal with all messages, just the one at a time, via [messageSet objectAtIndex:indexPath.row];
Related
I have a signature page, were the user can sign their name.
It needs to then be saved to NSDictionary, but i want to call a List of the keys to be text in a TableView for each row or cell.
so:
"viewImage = saved as object to key:Random Number"
That parts somewhat easy, the hard part is when i call it on the other Page to the TableView.
It Exits the App with Error"SIGABRT". Now all my Delegates are in place and working...i believe.
now heres some example code:
FirstPage.m
UIImagePNGRepresentation(viewImage);
NSMutableArray *innerArray = [[NSMutableArray array]init];
[innerArray addObject:viewImage];
[SignatureSave setObject:innerArray forKey:#"5599"];
simple Enough, but doesnt give me an error.
SecondPage.m
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
FirstPage *appShare = (FirstPage *)[[UIApplication sharedApplication] delegate];
NSArray *dataDuplicate = [[NSArray alloc]init ];
dataDuplicate = [appShare.SignatureSave allKeysForObject:#"innerArray"];
static NSString *CellIdentifier = #"Cell";
NSLog(#"%#",dataDuplicate);
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero]autorelease];
}
if (dataDuplicate != nil) {
cell.textLabel.text = [dataDuplicate objectAtIndex:indexPath.row];
}
else
{
UIAlertView *CellAlert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Error Loading content, Try Again Later." delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[CellAlert show];
[CellAlert release];
}
return cell;
}
#end
Now, How do i get the viewImage to save to the NSDictionary, to be able to call it on the SecondPage and display the name of the objects in the TableVIew?
I really don't understand whats your problem exactly.
first of all, is your dictionary a retained object?
//FirstPage.h
#property (nonatomic, retain) NSDictionary *SignatureSave;
//FirstPage.m
#synthesize SignatureSave;
…
UIImagePNGRepresentation(viewImage);
NSMutableArray *innerArray = [NSMutableArray array]; // using "array" is equivalent to alloc-init-autorelease
[innerArray addObject:viewImage];
[self.SignatureSave setObject:innerArray forKey:#"5599"];
// OR setting the array directly:
UIImagePNGRepresentation(viewImage);
NSArray *innerArray = [NSArray arrayWithObject:viewImage];
[self.SignatureSave setObject:innerArray forKey:#"5599"];
// OR even setting the image directly to the dictionary:
UIImagePNGRepresentation(viewImage);
[self.SignatureSave setObject:viewImage forKey:#"5599"];
now if you access the object by writing self. in front it will call the retain and your object will stay alive. Otherwise it would be autoreleased at the end of the method. This will fix the problem that your dictionary is maybe not present/available at table view creation and you don't have to use a singleton.
what are you trying to access with this code?
FirstPage *appShare = (FirstPage *)[[UIApplication sharedApplication] delegate];
with [[UIApplication sharedApplication] delegate] you get your application delegate (obviously). These are the MyAppNameAppDelegate files but you treat it as a FirstPage class.
Just NSLog() to check you get the right class, the one you expect.
NSLog(#"%#", [[[UIApplication sharedApplication] delegate] class]);
here you have a potential leak, you alloc-init but never release it:
NSArray *dataDuplicate = [[NSArray alloc]init ];
dataDuplicate = [appShare.SignatureSave allKeysForObject:#"innerArray"];
furthermore you can simplify it (will be autoreleased):
NSArray *dataDuplicate = [appShare.SignatureSave allKeysForObject:#"innerArray"];
and here you have another issue.
Why do you call all keys for the object #"innerArray"?
you don't have such an object and it's in many more cases wrong. innerArray was your previously named array in FirstPage.m but it is only for you as a developer to remember the variable better. After compilation it will have a cryptic name anyway. You could access your key #"5599" if you like but I don't think you want this. In your case you want to access all keys of the dictionary so simply call:
NSArray *dataDuplicate = [appShare.SignatureSave allKeys];
now you will have an array with all keys of your dictionary and you can access them like you do with objectAtIndex:.
NSString *keyName = [dataDuplicate objectAtIndex:indexPath.row];
cell.textLabel.text = keyName;
id theObject = [appShare.SignatureSave objectForKey:keyName]; // for example the image
Tell me if this solves your problems or tell me how I misunderstood your question.
I found the answer to this to be quit simple actually,
I ended up going with the Singleton Method instead of the Global Variable Method.
Now the Singleton Method looks terrifying but its quit simple, See here.
The main difference i noticed from the singleton method to the global method is,
Global method takes a lot of converting and re-converting.
Though the Singleton Method is working with a single object over many pages or classes.
Now i hope this will better assist people in the future also!
When the user click the next button, it generate random number and I would like to store the number into the array. My array is storing the last number only. Should I initialize the array outside the 'next' function? Moreover, I would like the 'back button' to read the array from the last in number. Please advise.
- (IBAction)Next:(id)sender {
// Do any additional setup after loading the view from its nib.
//generate random number - result is a range of 0-10
int randomnumber = (arc4random() % 10);
// Add the random number into array
[myArray addObject:[NSNumber numberWithInt:randomnumber]];
// easy way to look what is now in the array
NSLog([myArray description]);
NSString *fileName = [NSString stringWithFormat:#"File_no_%d", randomnumber +1];
//render a complete file-path out of our filename, the main-bundle and the file- extension
NSString *filePath=[[NSBundle mainBundle] pathForResource:fileName ofType:#"txt"];
//fetch the text content from that file
NSString *myText= [NSString stringWithContentsOfFile:filePath
encoding:NSUTF8StringEncoding
error:nil];
//hand that text over to our textview
TextView.text=myText;
}
- (IBAction)Back:(id)sender {
NSNumber *last_array_num = [myArray objectAtIndex:myArray.count - 1];
// read the file name based on the last number in array
NSString *fileName = [NSString stringWithFormat:#"File_no_%d", last_array_num ];
}
You say you are initializing the array within the Next method as well as adding to it? If so, the array needs to be initialized outside that method, and just once. This keeps your data intact, otherwise it is overwritten when you initialize it the next time.
You are adding to the array just fine, so that doesn't need to change at all. As for reading the number in your Back method, you simply need to have the following line of code:
EDIT: this is the code you would use to get the results you want from your array. Also, the formal approach is not to start with capital letters in your code unless it defines a class (like NSString). For methods, like this, you should use something like - (IBAction)backButton:(id)sender instead. It's not a big deal at all and your code will work fine, but it's just etiquette and keeps your code a bit less confusing in the long run. I have a feeling someone might say something about it later, so I'm just letting you know ahead of time. Anyway, here is the code you want
SECOND EDIT: Like you were thinking, you should make a variable that can be read from in the code. In your header file, add this
int arrayCount;
In your code, once myArray is created, set arrayCount
arrayCount = [myArray count];
This should also be done if add or remove any objects from the array.
Then in your action method, you can call the files
- (IBAction)Back:(id)sender {
NSString *filePath = [NSString stringWithFormat:#"File_no_%d", [[myArray objectAtIndex:arrayCount - 1] intValue]];
// make sure you aren't going beyond the bounds of the array;
if (arrayCount > 1) {
// decrease the count of the arrayCount;
arrayCount--;
}
}
Using this should allow you to move backwards in your array one step each time you click the button. Again, if this isn't what you are looking for, just let me know and we will get to the bottom of it
This is my first post on stackoverflow.com so please be kind (rewind) ;)
I have a navigation based application whose purpose is to display blog posts (title) in a Table View (with JSON).
The problem I ran into occurred when a cell got out of the screen and then back in.
I was getting a EXC_BAD_ACCESS (because I sent a message to a deallocated instance), so I struggled to understand where it came from and I finally found a solution. But the fact is I don't exactly understand how the problem occurs. That's why I need someone to enlighten me, I think this is fundamental understanding !
When the connection to the JSON web service has finished loading, I parse the JSON code to obtain a list of blog posts (recentPosts), then I create a BlogArticle object for each post (blogArticle), store it in a MutableArray iVar (allEntries) and insert a row in the Table View :
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[connection release];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
[responseData release];
NSError *error;
SBJsonParser *json = [[SBJsonParser new] autorelease];
NSDictionary *recentPostsData = [json objectWithString:responseString error:&error];
[responseString release];
NSArray *recentPosts = [recentPostsData objectForKey:#"posts"];
int i = 0;
for (NSDictionary *post in recentPosts) {
BlogArticle *blogArticle = [[BlogArticle alloc] initWithDictionary:post];
[allEntries insertObject:blogArticle atIndex:i];
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:i inSection:0]] withRowAnimation:UITableViewRowAnimationRight];
i++;
}
}
Here's the initialisation of the BlogArticle object which turned to be the origin of the problem :
- (id)initWithDictionary:(NSDictionary *)article
{
if (self = [super init])
{
// title = [[[article valueForKey:#"title"] gtm_stringByUnescapingFromHTML] copy];
// title = [[NSString alloc] initWithString:[[article valueForKey:#"title"] gtm_stringByUnescapingFromHTML]];
title = [[article valueForKey:#"title"] gtm_stringByUnescapingFromHTML];
}
return self;
}
So every Objective-C programmer who isn't as noobish as me is able to tell that title is never allocated before being assigned. If I uncomment one of the two lines above it will work. The program crashes exactly when I try to initialize a cell with that title variable, here :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
NSLog(#"indexPath.row = %i", indexPath.row);
// Configure the cell.
BlogArticle *article = [allEntries objectAtIndex:indexPath.row];
cell.textLabel.text = article.title;
return cell;
}
Now, what I need to understand is why it does compile/work without allocating the iVar and where exactly it causes trouble (or where exactly the content of title is released causing the program to crash).
Any good resource (noob friendly) about memory management in iOS environment would be much appreciated.
Thanks in advance :)
This line
title = [[article valueForKey:#"title"] gtm_stringByUnescapingFromHTML];
is allocating an autoreleased string. Essentially, think of it that an autoreleased string will get released at the end of the method (though it can last longer, it's useful to think of it that way).
You know the string is autoreleased because the name of the method gtm_stringByUnescapingFromHTML does not start with alloc, new, copy or mutableCopy.
You can add retain to this to stop it getting autoreleased:
title = [[[article valueForKey:#"title"] gtm_stringByUnescapingFromHTML] retain];
Now you own the string, and it will not get released until you say so.
The best summary I know of is Apple's own documentation here.
Well, the problem is, that you have to initialize your object, if you want to manage the memory of it on your own. Why should you manage now the memory of title?
Quite simple:
Every object reference, that is stored in an Array, Set, Dictionary etc. is managed by the Array, Dictionary and Set.
If you now just use this reference (by writing: "title = ...") in your cell, you will add the reference also to the cell. And now the cell is also responsible for the object-reference. So if the tableView wants to release your cells, which will happen from time to time to save memory, the cell will release your title-object. And this would cause the NSDitionary to be quite sad, since the NSDictionary wants to take care about the objects stored within itself.
So you could write the following in the tableView-method:
cell.textLabel.text = [article.title retain];
Or the commented lines of your own method.
That means, you will "raise" the storage-level of your object up and if it gets released, the storage level itself will be decreased by one.
If the storage-level will reach zero, it will be completely released (that should happen, if your tablecell is released AND your NSDIctionary)
I hope i could help you a bit :)
can any body tell me how to search NSMutable Arry in which objects are stored from xml feed
i have the following code
- (void) searchTableView {
NSString *searchText = searchBar.text;
NSMutableArray *searchArray = [[NSMutableArray alloc] init];
//blog entries is the nsmutable array in which objects are stored from RSS feed
for (NSMutableDictionary *dictionary in blogEntries)
{
NSArray *images=[dictionary objectForKey:#"image"];
NSArray *titlearray = [dictionary objectForKey:#"title"];
NSDictionary *imagesDic=[NSDictionary dictionaryWithObject:images forKey:#"image"];
NSDictionary *titlearrayDic=[NSDictionary dictionaryWithObject:titlearray forKey:#"title"];
[searchArray addObject:imagesDic];
[searchArray addObject:titlearrayDic];
}
//know the problem comes in below code i just want to compare title not image string as there any way to search only of title array not for both image in title some what like this For(nsstring *stemp in searcArray.titleArray etc)
for (NSString *sTemp in searchArray)
{
NSRange titleResultsRange = [sTemp rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (titleResultsRange.length > 0){
[copyListOfItems addObject:sTemp];
}}
the problem is that this code just saving title not image and if i save image then it also search in image string which i dont want to do. i want the user will search only by title then when he type something in textbox if search is true against some values then only thos e are displayed in table cell with title and image.
as this is RSS APPLiction and feeds are comming from xml feed
which
click here
bescially i am extracting this xml feed and em displaying image and title tage in table cell know i want to implement searchbar in it
Thanks....i am waiting for your response...
#mipadi is right - try using containsObject: first.
If that doesn't work, just a simple loop will do it - you can put in whatever matching criteria you want in there. e.g. This code searches by comparing the name properties :
- (id)searchArray:(NSArray *)haystack for:(id)needle {
for(id temp in haystack)
if ([temp name] isEqual:[needle name]])
return needle;
return nil;
}
Hope that helps.
NB If you're using your own objects in the array, you can use containsObject: if you have overridden isEqual: (and hash)
Depends on how you want to search. If you're just looking for a particular object, you can use containsObject:.
Without knowing more about what you want, it's tough to answer your question. But here are some starting points:
NSArray - Check out the methods starting like indexOfObject-; I think one of these probably does what you want. There's also filteredArrayUsingPredicate.
NSMutableArray - The only notable method here is filterUsingPredicate, I think.
Hope one of these helps you.
I have been trying to get this to work for about three solid days and get my mind around it. Can someone advise.
I have built the basics and they all work great but when I try to do that extra bit I cannot get my head around it.
I am trying to build a table of technical terms, from a plist. This is an indexed and sections table by the alphabet.
This works fine but when I then try to add the next level for each term's definition in a new viewcontroller I can't seem to get the code or the plist structure right.
At the moment I have created two plists. One with a dictionary of the alphabet in 26 arrays, within each array is a series of technical terms. All this works great.
Then I've created another plist of definitions as an array of dictionaries, one for each word/definition pair. I'm expecting to be passing the #"word" key from the view controller to the detailviewcontroller then picking up the #"definition". I don't know whether this is right or wrong(?)
My code shows the technical term table great but when a row is selected it crashes. I know it's to do with the code for passing the detailviewcontroller's reference so the detailview can pick up the definition - but I've no idea how to solve it. I've posted parts of my code here for someone to look at help. Any ideas?
NSString *wordPath = [[NSBundle mainBundle] pathForResource:#"newsortedglossary" ofType:#"plist"];
NSDictionary *wordDict = [[NSDictionary alloc] initWithContentsOfFile:wordPath];
self.words = wordDict;
[words release];
NSArray *wordArray = [[words allKeys] sortedArrayUsingSelector:#selector(compare:)];
self.wordKeys = wordArray;
NSString *definitionPath = [[NSBundle mainBundle] pathForResource:#"newnewdefinitionglossary" ofType:#"plist"];
NSDictionary *definitionDict = [[NSDictionary alloc] initWithContentsOfFile:definitionPath];
self.definitions = definitionDict;
[definitions release];
didSelectRow here.........
GlossaryDetailViewController *glossaryDetailViewController = [[GlossaryDetailViewController alloc]
initWithNibName:#"GlossaryDetailView" bundle:nil];
NSLog(#"did select-2"); // CRASHES HERE with NSDictionary may not respond to objectAtIndex
glossaryDetailViewController.definition = [self.words objectAtIndex:indexPath.row];
NSLog(#"did select-3");
[self.navigationController pushViewController:glossaryDetailViewController animated:YES];
NSLog(#"did select-4");
[glossaryDetailViewController release];
detailViewController here.......
- (void)viewDidAppear:(BOOL)animated {
NSLog(#"didappear");
self.glossaryWordDefinition.text = [definition objectForKey:#"definition"];
It seems that you are trying to access the members of dictionary by using an index, instead of using a key to lookup the associated value.
In your didSelectRow you probably want this:
glossaryDetailViewController.definition = [self.wordKeys objectAtIndex:indexPath.row];
The difference is that now you are trying access the members of an array with the index.