How to return all messages from array - ios

NSArray *mystring = [[NSArray alloc]init];
mystring = _fetchedResultsController.fetchedObjects;
// NSString *string = [NSString stringWithFormat:#"%#",mystring];
_messages = [[NSMutableArray alloc]initWithArray:mystring];
for (Message *msg in _messages) {
[mystring lastObject];
NSString *text = [NSString stringWithFormat:#"%#",msg.text];
self.messages = [[NSMutableArray alloc] initWithObjects:
[[JSQMessage alloc] initWithSenderId:kJSQDemoAvatarIdWoz
senderDisplayName:_user_email
date:[NSDate distantPast]
text:text],
nil];
My array contain right now 3 messages for example and then on the app I only can see the last message from the array. I know the problem which is maybe I'm just assuming: or something wrong with my declaration of the array maybe .first object or .last object or .count needed to be set in some way Or most likely I'm missing something in the [JSQMESSAGE] object that will return all messages array into the app. Either way that's way I'm here for that, so if some one can guideline me on what to do, for sure I can't call the [[JSQMESSAGE ALLOC] a million time's...
I need some example with NSINTEGER or something I just need all messages to be displayed how can I do that? also How can I see all the sender messages not just the received messages?
And also in general some help with this un clear FrameWork will be great.
I'm using core data with fetchedResultsController.
And JSQMessages framework.
The simulator Screen shot image:
http://postimg.org/image/gkjpssbbd/

If I'm reading this correctly it looks like you're re-initializing your array with the objects of what appears to be another array. This would just add the JSQMessages array to your self.messages array as an object, with the object actually containing the messages. I don't know anything about JSQMessage but it seems that what it's returning to you is already an array of messages. Simply set your self.messages array equal to the JSQMessages array after initializing self.messages.
If this is not the case then actually read the documentation for that framework.

Related

Can't have access to NSDictionary in NSArray

I have a very strange behaviour with NSArray.
Firstly, i parsed an XML file and return a valid NSArray with NSDictionary inside:
NSArray *arrayOfDict = [parser parseWithXMLFile:filename];
In debugger it's fully valid. Then, i want to proccess all dictionaries in this array:
NSMutableArray* arrayOfProducts = [[NSMutableArray alloc] init];
for (NSDictionary* dict in arrayOfDict) {
Product* product = [[Product alloc] initWithName:dict[#"name"]
type:dict[#"type"]
imageName:dict[#"image"]
description:dict[#"description"]];
[arrayOfProducts addObject:product];
[product release];
}
And in this loop is a problem: a dict variable has value nil. And i don't know what to do with this. In debugger i evaluate value of arrayOfDict[someIndex] and get a right value, but in the programm itself it doesn't work.
May be it's the problem with MRR, i don't feel myself confidenly while using MRR and there is a mistake of using it.
P.S. I know that using MRR is stupid today, but in this project i must use it.

Checking If One Array Contains An Object of Another Array In Objective C

I am using below function to check whether if an object in an array is present in another array. If the object not present, then I will ADD that object to the new array, or else that object will NOT be included in the new array that I instantiated.
+ (NSMutableArray *)loadUngroupedSpeakerList
{
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *speakerList = [[NSMutableArray alloc] init];
NSArray *speakerIDList = [userDefaults objectForKey:DATA_SPEAKER_IDLIST];
NSArray *speakerIDListGrouped = [userDefaults objectForKey:DATA_SPEAKER_IDLIST_GROUPED];
//**** this is for checking the contents of speakerIDListGrouped ****//
for(NSString *speakerID in speakerIDListGrouped)
{
NSLog(#"FLOWCHECK~ loadUngroupedSpeakerList check content:%#", speakerID);
}
for(NSString *speakerID in speakerIDList)
{
if(![speakerIDListGrouped containsObject:speakerID])
{
NSLog(#"FLOWCHECK~ loadUngroupedSpeakerList: speakerID: %#", speakerID);
NSDictionary *speakerDict = [userDefaults dictionaryForKey:[NSString stringWithFormat:#"%#%#", DATA_SPEAKER_DICT, speakerID]];
[speakerList addObject:speakerDict];
}
}
return speakerList;
}
In the above code, speakerList contains all the speakerIDs. While speakerIDListGrouped only contains the speakerIDs that are used in a group. My function needs to eliminate all the speakerIDs used in a group so I did it in a way just like the above code.
My Problem:
When I run the code, I notice that even if speakerIDListGrouped contains the object in speakerIDList, these two lines would still be executed
NSDictionary *speakerDict = [userDefaults dictionaryForKey:[NSString stringWithFormat:#"%#%#", DATA_SPEAKER_DICT, speakerID]];
[speakerList addObject:speakerDict];
Whereas to I understand, It should not happen. Because I only allowed them to be executed only if speakerIDList does not contain that object.
This is the log when I execute the code:
2015-06-15 19:31:24.849 soulbeats[1936:433953] FLOWCHECK~ loadUngroupedSpeakerList check content:72243140485836704
2015-06-15 19:31:24.850 soulbeats[1936:433953] FLOWCHECK~ loadUngroupedSpeakerList check content:7782687177520836128
2015-06-15 19:31:24.850 soulbeats[1936:433953] FLOWCHECK~ loadUngroupedSpeakerList: speakerID: 72243140485836704
2015-06-15 19:31:24.851 soulbeats[1936:433953] FLOWCHECK~ loadUngroupedSpeakerList: speakerID: 7782687177520836128
As can be seen, speakerIDListGrouped DOES contain the two objects. However, when I tried replacing the string inside the lower for loop by hardcoding it to one of the objects I printed on Log, which was 72243140485836704. The function now works properly, I mean it didn't execute the two lines I showed before.
I am now confused. What is the difference between the string I hardcoded and the one that was obtained from the array? The contents are the same.
Many Thanks!
I did the same thing it is working fine...
NSMutableArray *speakerList = [[NSMutableArray alloc] init];
NSArray *speakerIDList = #[#"a",#"b",#"c",#"d",#"e"];
NSArray *speakerIDListGrouped =#[#"a",#"b",#"f",#"g",#"h"];
for(NSString *speakerID in speakerIDListGrouped)
{
NSLog(#"%#", speakerID);
}
for(NSString *speakerID in speakerIDList)
{
if(![speakerIDListGrouped containsObject:speakerID])
{
NSLog(#"FLOWCHECK~ loadUngroupedSpeakerList: speakerID: %#", speakerID);
[speakerList addObject:speakerID];
}
}
There might be some issue with the objects inside the array....
This answer will help other's. It's very simple, use following method of NSArray
id commonObject = [array1 firstObjectCommonWithArray:array2];
Ref: https://developer.apple.com/documentation/foundation/nsarray/1408825-firstobjectcommonwitharray?language=objc

Tricky Object Sorting and Removing from NSMutableArray

I have an array of objects (that contain a message), every object has the same structure. It has a message property which is an NSDictionary. One dictionary looks like this:
<message: {
keyCreateDate = "06/08/14 21:23";
keyMessage = Lorem ipsum;
keyReceiverChannel = sampleString;
keySenderUser = SampleName;
},...
My goal is to make an "inbox" where i would like to display the newest messages from every user in each cell. I want the show only the newest messages from each user, like the Fb messages, What'sApp or iMessage inbox, every cell in the table view represents the recent message from a friend. It looks very easy, but it's much harder than i imaged. So i need to remove every message from every friend, but always keep newest one. Actually i can remove all message from one user, but can't keep the newest while removing the others. Is it possible to do this?
I can remove all message for one specified user with this code:
NSMutableArray *originalArray = [[NSMutableArray alloc]initWithArray:message];
NSMutableArray *objectsToRemove = [[NSMutableArray alloc]init];
NSMutableArray *cloneArray = [NSMutableArray arrayWithArray:originalArray];
for (NMessage *messageObject in originalArray) {
if ([messageObject.message[#"keySenderUser"] isEqual:usernameString]) {
[objectsToRemove addObject:messageObject];
}
}
if ([objectsToRemove count]>0) {
[cloneArray removeObjectsInArray:objectsToRemove];
NSLog(#"deleted: %#", objectsToRemove);
self.messagesArray = [[NSMutableArray alloc]initWithArray:cloneArray];
I think it would be the easier, if i could somehow add an exception to the [cloneArray removeObjectsInArray:objectsToRemove]; line, that doesn't let to remove the newest ones. But it's also a problem that i need to sort the messages based on the keySenderUser before i delete them. My actual code can't do that, it can find only one pre-defined user's message and remove all of them. Please share with me if you have any idea. Thanks in advance.
I feel bottom up is better in your case where you build a new array which contains latest message dictionary.
The solution is as below.
1. sort the array using date.
2. Create a new list for holding user messages.
2. Loop through each object check whether the user is already present, If not add it to the created list.
The code solution is below, pass in your array of messaged, which would give a list of messages which are latest for an user.
-(NSArray *) GetLatestMessageListForEveryUser:(NSArray *) array
{
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
NSArray *sortedArray = [array sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
NSDate *obj1Date = [formatter dateFromString: [(NSDictionary *)obj1 objectForKey:#"keyCreateDate" ] ];
NSDate *obj2Date = [formatter dateFromString:[(NSDictionary *)obj2 objectForKey:#"keyCreateDate" ] ];
return ([obj1Date earlierDate:obj2Date] == obj1Date);
}];
NSMutableArray *messageArray = [NSMutableArray array];
NSMutableArray *usersArray = [NSMutableArray array];
for (NSDictionary *messageDictionary in sortedArray)
{
NSString *userName = [messageDictionary objectForKey:#"keySenderUser"];
if (![usersArray containsObject:userName])
{
[usersArray addObject:userName];
[messageArray addObject:messageDictionary];
}
}
return messageArray;
}

Reading a .csv into NSObjects and then sorting them by different criterias

This is more a open question than an error-related question, so if you don't like to answer these kinds of questions, please don't flame.
I have a huge (!) list of ships in a .csv file, separated by ,
The matrix is organised like this:
repeated with different data about 500 times.
Now, I want this to be read into objects, which can be used further to populate a UITableView
Currently, I hard-code data into the object files, like this
arrayWithObjectsForTableView = [[NSMutableArray alloc] init];
if ([boatsFromOwner isEqualToString:#"Owner1"]) {
cargoShips* ship = [[cargoShips alloc]init];
ship.name = #"name1";
ship.size = 1000;
ship.owner = #"Owner1";
[self.boatsForOwner addObject:ship];
ship = [[cargoShips alloc]init];
ship.name = #"Name 2";
ship.size = 2000;
ship.owner = #"Owner2";
And so on and on with if-else's. This is a bad method, as
1) Its boring and takes a long time
2) It takes even more time if I want to update the information.
So, I figured it would be smarter to read programmatically from the matrix instead of doing it myself. Yeah, captain obvious came for a visit to my brain.
So, to the question!
How can I read the .csv file that looks like this:
add the ships of, say, owner, to a NSMutableArray, in the shape of objects. (So they can be used to feed my UITableView with ships.
I would also like to have the option to sort by different stuff, like Country of build, Operator etc. How can I make code that feeds relevant ships read from the .csv into objects?
I don't know much programming, so in-depth answers would be very appreciated.
The depth of your processing will determine what sort of data structure is required for this task. This is the method I would use:
1: Read the .csv file into one giant NSString object:
NSString *file = [[NSString alloc] initWithContentsOfFile:yourCSVHere];
2: Get the individual lines:
NSArray *allLines = [file componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
3: For each line, get the individual components:
for (NSString* line in allLines) {
NSArray *elements = [line componentsSeparatedByString:#","];
// Elements now contains all the data from 1 csv line
// Use data from line (see step 4)
}
4: This is where it's up to you. My first thought would be to create a class to store all your data. For example:
#interface Record : NSObject
//...
#property (nonatomic, copy) NSString *name
#property (nonatomic, copy) NSString *owner
// ... etc
#end
4a: Then, back in step 3 create a Record object for each line and then put all the Record objects into a separate NSArray (something with larger scope!).
5: Use your NSArray that contains all your Record objects as the data source for your UITableView.
The implementation of Steps 4 and 5 are up to you. That's probably how I would do it though for a medium sized .csv file.
EDIT: Here's how to generate the Records.
//
NSMutableArray *someArrayWithLargerScope = [[NSMutableArray alloc] init];
//
NSString *file = [[NSString alloc] initWithContentsOfFile:yourCSVHere];
NSArray *allLines = [file componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet];
for (NSString* line in allLines) {
NSArray *elements = [line componentsSeparatedByString#","];
Record *rec = [[Record alloc] init];
rec.name = [elements objectAtIndex:0];
rec.owner = [elements objectAtIndex:1];
// And so on for each value in the line.
// Note your indexes (0, 1, ...) will be determined by the
// order of the values in the .csv file.
// ...
// You'll need one `Record` property for each value.
// Store the result somewhere
[someArrayWithLargerScope addObject:rec];
}
In terms of the CSV parsing, assuming you can spend the memory it's probably easiest to read in the whole thing to an NSString, split that on newlines and then split each line on commas, essentially as PLPiper suggests.
At that point I'd take a detour into key-value coding. Give your columns in the CSV file exactly the same name as the properties on your runtime object. Then you can just write something like:
// this method will create an object of the given type then push the values
// from valueRow to the properties named by headingRow. So, ordinarily,
// headingRow will be the first row in your CSV, valueRow will be any other
- (id)populatedObjectOfType:(Class)type withHeadingRow:(NSArray *)headingRow valueRow:(NSArray *)valueRow
{
// we need the count of fields named in the heading row to
// match the count of fields given in this value row
if([headingRow count] != [valueRow count]) return nil;
// autorelease if you're not using ARC
id <NSObject> newInstance = [[type alloc] init];
// we need to enumerate two things simultaneously, so
// we can fast enumerate one but not the other. We'll
// use good old NSEnumerator for the other
NSEnumerator *valueEnumerator = [valueRow objectEnumerator];
for(NSString *propertyName in headingRow)
{
[newInstance setValue:[valueEnumerator nextObject] forKey:propertyName];
}
return newInstance;
}
... elsewhere ....
CargoShip *newShip = [self populateObjectOfType:[CargoShip class] withHeadingRow:[csvFile objectAtIndex:0] valueFor:[csvFile objectAtIndex:1]];
The main caveat is that the built-in mechanisms will convert between scalars and objects but not between objects of different types. So if you had all NSString and C integer types (short, int, NSUInteger, etc) you'd be fine, but if you had some NSStrings and, say, some NSNumbers then you would end up with strings stored in the number slots. It looks like you're using C integer types (as is quite normal) so you should be fine.
In terms of filtering, you can use NSPredicates. For example, suppose you had an array of CargoShips and wanted every one with a size of at least 500:
NSArray *bigShips = [allShips filteredArrayUsingPredicate:
[NSPredicate predicateWithFormat:#"size > 500"]];
Similarly, for sorting you can throw some NSSortDescriptors at the problem. E.g.
NSArray *shipsSortedBySize = [allShips sortedArrayUsingDescriptors:
#[[NSSortDescriptor sortDescriptorWithKey:#"size" ascending:YES]]];
you can use this link,
https://github.com/davedelong/CHCSVParser
It is the .csv parser and CHCSVParser can be configured to parse other "character-seperated" file formats, such as "TSV" (tab-seperated) or comma seperated.

What's the standard convention for creating a new NSArray from an existing NSArray?

Let's say I have an NSArray of NSDictionaries that is 10 elements long. I want to create a second NSArray with the values for a single key on each dictionary. The best way I can figure to do this is:
NSMutableArray *nameArray = [[NSMutableArray alloc] initWithCapacity:[array count]];
for (NSDictionary *p in array) {
[nameArray addObject:[p objectForKey:#"name"]];
}
self.my_new_array = array;
[array release];
[nameArray release];
}
But in theory, I should be able to get away with not using a mutable array and using a counter in conjunction with [nameArray addObjectAtIndex:count], because the new list should be exactly as long as the old list. Please note that I am NOT trying to filter for a subset of the original array, but make a new array with exactly the same number of elements, just with values dredged up from the some arbitrary attribute of each element in the array.
In python one could solve this problem like this:
new_list = [p['name'] for p in old_list]
or if you were a masochist, like this:
new_list = map(lambda p: p['name'], old_list)
Having to be slightly more explicit in objective-c makes me wonder if there is an accepted common way of handling these situations.
In this particular case Cocoa is not outdone in succinctness :)
NSArray *newArray = [array valueForKey:#"name"];
From the NSArray documentation:
valueForKey:
Returns an array containing the
results of invoking valueForKey: using
key on each of the receiver's objects.

Resources