Advertise here




Advertise here

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Sign In with Google Sign In with OpenID
Please do not post the same thing multiple times. The board software automatically flags certain posts as needing moderator attention. This happens the most often for new users. I'm pretty sure this is made clear at the time you attempt to post. Posting the same thing over and over again just makes that many more posts the moderators have to weed through later. This makes us sad. Don't make us sad. If your post/thread doesn't appear, just wait a while. Don't post it again. If it hasn't shown up by the next day, then you can try again. I normally go through posts in the mornings, and try to check a few times throughout the day, but I'm not here 24/7. There will typically be a significant delay before posts are approved. Just be patient.

Method Help

ad1269ad1269 Posts: 29New Users
Hi, I have a method where the chat bubbles are displayed on the table view. I needed a way to detect whether a message was received or sent. I made another post about this and domele told me to use this method: - (void)addText:(NSString *)text received:(BOOL)yesOrNo; However, I can't figure out how to do that when my conditional is inside this method:


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

static NSString *CellIdentifier = @"Cell";

UIImageView *balloonView;
UILabel *label;

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
tableView.separatorStyle = UITableViewCellSeparatorStyleNone;

balloonView = [[UIImageView alloc] initWithFrame:CGRectZero];
balloonView.tag = 1;

label = [[UILabel alloc] initWithFrame:CGRectZero];
label.backgroundColor = [UIColor clearColor];
label.tag = 2;
label.numberOfLines = 0;
label.lineBreakMode = UILineBreakModeWordWrap;
label.font = [UIFont systemFontOfSize:14.0];

UIView *message = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, cell.frame.size.width, cell.frame.size.height)];
message.tag = 0;
[message addSubview:balloonView];
[message addSubview:label];
[cell.contentView addSubview:message];

}
else
{
balloonView = (UIImageView *)[[cell.contentView viewWithTag:0] viewWithTag:1];
label = (UILabel *)[[cell.contentView viewWithTag:0] viewWithTag:2];
}

NSString *text1 = [messages objectAtIndex:indexPath.row];
CGSize size = [text1 sizeWithFont:[UIFont systemFontOfSize:14.0] constrainedToSize:CGSizeMake(240.0f, 480.0f) lineBreakMode:UILineBreakModeWordWrap];

UIImage *balloon;



if(MESSAGE RECEIEVED)
{
balloonView.frame = CGRectMake(0.0, 2.0, size.width + 28, size.height + 15);
balloon = [[UIImage imageNamed:@"grey.png"] stretchableImageWithLeftCapWidth:24 topCapHeight:15];
label.frame = CGRectMake(16, 8, size.width + 5, size.height);
}
else
{

balloonView.frame = CGRectMake(320.0f - (size.width + 28.0f), 2.0f, size.width + 28.0f, size.height + 15.0f);
balloon = [[UIImage imageNamed:@"pink.png"] stretchableImageWithLeftCapWidth:24 topCapHeight:15];
label.frame = CGRectMake(307.0f - (size.width + 5.0f), 8.0f, size.width + 5.0f, size.height);
}

balloonView.image = balloon;
label.text = text1;

return cell;
}


I've tried just copying and pasting the code into the suggested method and also copying the :(NSString *)text received:(BOOL)yesOrNo; to the beginning of this method but none of the solutions work. I really am a newbie at this so I was hoping someone could help.

Thanks,
AD
Post edited by ad1269 on
«1

Replies

  • BrianSlickBrianSlick Posts: 9,316Tutorial Authors, Registered Users
    1. Don't make duplicate threads for the same issue.

    2. From what I gather here, the messages array contains only strings. This means you are not keeping enough information about a given message. You will need to make a model object (see link in my signature) that keeps track of not only the message text, but whether it was incoming or outgoing. And then perhaps sender ID, time stamp, etc. So, most of the work needs to be done wherever you are processing messages, not here. Here will just be a matter of looking at the property and displaying accordingly.
  • ad1269ad1269 Posts: 29New Users
    How would I implement this method:- (void)addText:(NSString *)text received:(BOOL)yesOrNo;
    My conditional is inside the - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath; I am a total newbie.


    My code is below:

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    I DECLARED ALL THE VARIABLES HERE.
    if(DATA RECEIVED)
    {
    balloonView.frame = CGRectMake(320.0f - (size.width + 28.0f), 2.0f, size.width + 28.0f, size.height + 15.0f);
    balloon = [[UIImage imageNamed:@"green.png"] stretchableImageWithLeftCapWidth:24 topCapHeight:15];
    label.frame = CGRectMake(307.0f - (size.width + 5.0f), 8.0f, size.width + 5.0f, size.height);
    }
    else if (DATA WAS SENT)
    {
    balloonView.frame = CGRectMake(0.0, 2.0, size.width + 28, size.height + 15);
    balloon = [[UIImage imageNamed:@"grey.png"] stretchableImageWithLeftCapWidth:24 topCapHeight:15];
    label.frame = CGRectMake(16, 8, size.width + 5, size.height);
    }

    }

    My conditional is inside - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath; method so I don't know how to implement that method. Please I really need help.

    I'm sorry if this is a total newbie question. iOS programming is also my first programming language and everyone tells me it is harder than the rest. I hope you guys understand.

    Thanks,
    AD
    Post edited by ad1269 on
  • BrianSlickBrianSlick Posts: 9,316Tutorial Authors, Registered Users
    The method that you were given was a partial answer. It was a suggestion of an approach, not a complete solution. So there really is no reason to keep running around asking how to implement that particular method.

    Now then, while I'm sure you're being honest about being a newbie, it's also a cop-out. You're messing with game kit and blue tooth, skills that I don't currently have. So either you know more than you are letting on, or all you have done so far is copy-paste stuff from other tutorials. You cannot copy-paste your way into being a good coder. At some point you have to take the time to understand this stuff.

    No one here has a problem with helping you learn, but nobody is going to just hand you code so that you can go on your way until you smack into the next problem. Asking questions that demonstrate that you are trying to learn will get you a lot farther than simply asking the same question over and over again.

    So, I suggest you reread my previous answer, go read the thread I linked to you, put some good honest thought into a solution, and then if necessary come back and ask specific questions about the technique.
  • ad1269ad1269 Posts: 29New Users
    Okay, I'm sorry. I looked into the link you gave me and read your answer. So what you are suggesting is add the message received to a model class that has defined variables such as message received, message text... and then import it into my view controller and set the key as received and then call it later in my other method.

    I just want to clarify and I'm sorry about before.
  • ad1269ad1269 Posts: 29New Users
    I looked at the model tutorial you wrote and I just want to clarify whether the following code would work.


    NSString* str;

    [dic setObject:str forKey:@"received"]; // this line
    [tbl reloadData];
    NSUInteger index = [dic count] - 1;
    [tbl scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES];

    and


    if([dic objectForKey:@"received"]) //specifically this line
    {
    balloonView.frame = CGRectMake(320.0f - (size.width + 28.0f), 2.0f, size.width + 28.0f, size.height + 15.0f);
    balloon = [[UIImage imageNamed:@"green.png"] stretchableImageWithLeftCapWidth:24 topCapHeight:15];
    label.frame = CGRectMake(307.0f - (size.width + 5.0f), 8.0f, size.width + 5.0f, size.height);
    }
    else
    {
    balloonView.frame = CGRectMake(0.0, 2.0, size.width + 28, size.height + 15);
    balloon = [[UIImage imageNamed:@"grey.png"] stretchableImageWithLeftCapWidth:24 topCapHeight:15];
    label.frame = CGRectMake(16, 8, size.width + 5, size.height);
    }

  • BrianSlickBrianSlick Posts: 9,316Tutorial Authors, Registered Users
    Alright, not sure how you read that and came away with the suggestion to use a dictionary. That would be the total opposite of the recommendation, actually.

    What you want is a simple model object along these lines:
    @interface ADMessage : NSObject
    {
    }

    @property (nonatomic, copy) NSString *messageBody;
    @property (nonatomic, assign, getter = isReceived) BOOL received;
    If that is all you need, then you can stop here. If you need more, add more. Perhaps a date property for the message sent date/time. Perhaps a string property to identify the sender.

    Then your code would become:
    ADMessage *message = [[self messages] objectAtIndex:[indexPath row]];

    if ([message isReceived])
    {
    // Whatever
    }
    else
    {
    // Whatever else
    }
    And then to demonstrate why the previous answer was insufficient, here is how you might use it with your model object:
    - (void)addText:(NSString *)text received:(BOOL)yesOrNo
    {
    ADMessage *message = [[ADMessage alloc] init];

    [message setMessageBody:text];
    [message setReceived:yesOrNo];

    [[self messages] addObject:message];

    // If not using ARC, release the message
    }
    Before, all you had was a string to represent each message. All the string provides is the body, it does not provide any other information. Now, you have the extra property, and can store that value. Pretty much the only way you could have made this method work with your previous structure would have been to use two separate arrays:
    - (void)addText:(NSString *)text received:(BOOL)yesOrNo
    {
    if (yesOrNo)
    [[self receivedArray] addObject:text];
    else
    [[self sentArray] addObject:text];
    }
    Using the model object is a better approach for a variety of reasons. Either way, the method you were given before could not have been used by itself without you making additional changes of some kind. That's why you should not ask how to shoehorn a particular method into a specific part of your app. It may not make sense in that spot, it may not make sense at all, and even if it does make sense, you may have to make adjustments in order to utilize it.

    But at the end of the day, you learn the most by trying. There is never a reason to come here and ask if code would work. Try it for yourself, then you will know. If it does work, then you don't need to worry too much at this stage whether or not it could be better. Those things come with experience. If it doesn't work, then you need to decide if you feel like it should work, and then you can ask those kinds of questions. Here is what I expected, here is what I did, but unfortunately here is what happened, this is not what I expected, what does this mean?
    Post edited by BrianSlick on
  • ad1269ad1269 Posts: 29New Users
    Hi I tried this code but the app crashed when I pressed the send button. I looked at the crash log and it has something to do with the isReceived property.

    2012-08-24 14:23:02.698 iVoiceChat[88604:207] -[__NSCFString isReceived]: unrecognized selector sent to instance 0xe02d6b0
    2012-08-24 14:23:02.700 iVoiceChat[88604:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString isReceived]: unrecognized selector sent to instance 0xe02d6b0'
    *** First throw call stack:
    (0x1f36022 0x1c21cd6 0x1f37cbd 0x1e9ced0 0x1e9ccb2 0x54ae 0x4eec54 0x4ef3ce 0x4dacbd 0x4e96f1 0x492d42 0x1f37e42 0x13f1679 0x13fb579 0x13804f7 0x13823f6 0x1381ad0 0x1f0a99e 0x1ea1640 0x1e6d4c6 0x1e6cd84 0x1e6cc9b 0x17797d8 0x177988a 0x454626 0x1db8 0x1d15)
    terminate called throwing an exceptionsharedlibrary apply-load-rules all
    Current language: auto; currently objective-c
    (gdb)

    The code you gave me for the object header I kept the same and for the implementation file I just synthesized the variables. The concept of model objects is a little bit hard for me to grasp. I am going to add a date method in the future once I get a little bit better understanding of models by reading books and using google.

    Thanks, and I just want to say I really appreciate your help,
    AD
  • BrianSlickBrianSlick Posts: 9,316Tutorial Authors, Registered Users
    Looks like you are dealing with strings instead of message objects. You need to fix that.
  • ad1269ad1269 Posts: 29New Users
    By dealing with strings do you mean the message I received is in the string form or I'm adding strings to the array.
  • BrianSlickBrianSlick Posts: 9,316Tutorial Authors, Registered Users
    I don't know, since you haven't shown relevant code for either situation. Could be both.
  • ad1269ad1269 Posts: 29New Users
    When a message is received, it is in NSData form which I convert to NSString and add to the array. So are you saying I need to add the ADMessage object to the array.
  • BrianSlickBrianSlick Posts: 9,316Tutorial Authors, Registered Users
  • Duncan CDuncan C Posts: 8,034Tutorial Authors, Registered Users
    ad1269 said:

    When a message is received, it is in NSData form which I convert to NSString and add to the array. So are you saying I need to add the ADMessage object to the array.

    You need to add data objects to your array, not strings. Then the data objects can contain all the information you need for each entry in your table view. If you need 3 strings, a boolean, and an image, you can expand your data object ("ADMessage") to add properties for those extra elements.

    When you receive NSData from your remote host:

    Convert the data to a string
    Create an ADMessage object
    Install the string into the ADMessage object
    Save the ADMessage object to your array.
    Regards,

    Duncan C
    WareTo

    mug

    Animated GIF created with Face Dancer, available for free in the app store.
  • ad1269ad1269 Posts: 29New Users
    I have the code below where I'm processing the messages.
    How do I set the value of the ADMessage Object to the value of the string.
    I'm a little confused there.

    - (void) receiveData:(NSData *)data
    fromPeer:(NSString *)peer
    inSession:(GKSession *)session
    context:(void *)context {
    //---convert the NSData to NSString---
    NSString* str;
    str = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"New Message"
    message:str
    delegate:self
    cancelButtonTitle:@"OK"
    otherButtonTitles:nil];
    [alert show];

    ADMessage *message = data contained in string; //ADMessage Object

    }

    Just in case you need my send data method here it is.

    - (void) mySendDataToPeers:(NSData *) data
    {
    if (currentSession)
    [self.currentSession sendDataToAllPeers:data
    withDataMode:GKSendDataReliable
    error:nil];
    }

    -(IBAction) btnSend:(id) sender
    {
    //---convert an NSString object to NSData---
    NSData* data;
    NSString *str = [NSString stringWithString:txtMessage.text];
    data = [str dataUsingEncoding: NSASCIIStringEncoding];
    [self mySendDataToPeers:data];

    if(![txtMessage.text isEqualToString:@""])
    {
    [messages addObject:txtMessage.text];
    [tbl reloadData];
    NSUInteger index = [messages count] - 1;
    [tbl scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES];

    txtMessage.text = @"";
    }
    }
    I haven't added the ADMessage Object to the send method yet.
    Post edited by ad1269 on
  • BrianSlickBrianSlick Posts: 9,316Tutorial Authors, Registered Users
    Come on now, I already gave an example. You're not reading my posts very carefully.
  • ad1269ad1269 Posts: 29New Users
    Oh sorry, I forgot about that, I have set the value of the ADMessage to the string and added the object to the array.
    Now I just have to test it.

    Here is my code:


    [message setMessageBody:str];

    [messages addObject:message];
    [tbl reloadData];
    NSUInteger index = [messages count] - 1;
    [tbl scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES];


  • ad1269ad1269 Posts: 29New Users
    Everything seems to be working but now there is a new problem. I have to get the size of the text to figure out how big the speech bubble should be but I can't do that because i'm not storing a string in the array, I'm storing an object. How would I load the string from inside the object. Didn't you say that you would cover that in a later tutorial.
    Here is my code:


    NSString *text = [messages objectAtIndex:indexPath.row];
    CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:14.0] constrainedToSize:CGSizeMake(240.0f, 480.0f) lineBreakMode:UILineBreakModeWordWrap];

    I'm thinking that I would need to do something like this:

    ADMessage *text = [messages objectAtIndex:indexPath.row];
    NSString *msg = the messageBody property of text // this is the line I need

    CGSize size = [msg sizeWithFont:[UIFont systemFontOfSize:14.0] constrainedToSize:CGSizeMake(240.0f, 480.0f) lineBreakMode:UILineBreakModeWordWrap];
  • Duncan CDuncan C Posts: 8,034Tutorial Authors, Registered Users
    ad1269 said:

    Everything seems to be working but now there is a new problem. I have to get the size of the text to figure out how big the speech bubble should be but I can't do that because i'm not storing a string in the array, I'm storing an object. How would I load the string from inside the object. Didn't you say that you would cover that in a later tutorial.
    Here is my code:



    NSString *text = [messages objectAtIndex:indexPath.row];
    CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:14.0] constrainedToSize:CGSizeMake(240.0f, 480.0f) lineBreakMode:UILineBreakModeWordWrap];

    I'm thinking that I would need to do something like this:

    ADMessage *text = [messages objectAtIndex:indexPath.row];
    NSString *msg = the messageBody property of text // this is the line I need

    CGSize size = [msg sizeWithFont:[UIFont systemFontOfSize:14.0] constrainedToSize:CGSizeMake(240.0f, 480.0f) lineBreakMode:UILineBreakModeWordWrap];
    Oh boy. You don't know the basics of Objective C, do you?

    Don't call your data object "text". It is not text, it is a data object that has a string property. That's going to confuse you, and anybody who works on your code in the future. Call it something like cellData.

    If you have an ADMessage object called cellData, you'd get to the messageBody property with the expression cellData.messageBody


    ADMessage *cellData = [messages objectAtIndex:indexPath.row];
    NSString *msg = cellData.messageBody;

    CGSize size = [msg sizeWithFont:[UIFont systemFontOfSize:14.0] constrainedToSize:CGSizeMake(240.0f, 480.0f) lineBreakMode:UILineBreakModeWordWrap];
    Regards,

    Duncan C
    WareTo

    mug

    Animated GIF created with Face Dancer, available for free in the app store.
  • ad1269ad1269 Posts: 29New Users
    Okay thanks for the clarification. I tried the code but my application still crashes with the following crash log:

    2012-08-24 20:27:29.809 iVoiceChat[12491:207] -[ADMessage sizeWithFont:constrainedToSize:lineBreakMode:]: unrecognized selector sent to instance 0x92471d0

    My code is below and I have absolutely no idea what I'm doing wrong.


    ADMessage *cellData = [messages objectAtIndex:indexPath.row];

    NSString *msg = cellData.messageBody;

    CGSize size = [msg sizeWithFont:[UIFont systemFontOfSize:14.0] constrainedToSize:CGSizeMake(240.0f, 480.0f) lineBreakMode:UILineBreakModeWordWrap];

    UIImage *balloon;

    if([cellData isReceived])
    {
    balloonView.frame = CGRectMake(320.0f - (size.width + 28.0f), 2.0f, size.width + 28.0f, size.height + 15.0f);
    balloon = [[UIImage imageNamed:@"green.png"] stretchableImageWithLeftCapWidth:24 topCapHeight:15];
    label.frame = CGRectMake(307.0f - (size.width + 5.0f), 8.0f, size.width + 5.0f, size.height);
    }
    else
    {
    balloonView.frame = CGRectMake(0.0, 2.0, size.width + 28, size.height + 15);
    balloon = [[UIImage imageNamed:@"grey.png"] stretchableImageWithLeftCapWidth:24 topCapHeight:15];
    label.frame = CGRectMake(16, 8, size.width + 5, size.height);
    }


    Thanks,
    AD
  • BrianSlickBrianSlick Posts: 9,316Tutorial Authors, Registered Users
    You are sending the sizeWithFont message to an ADMessage object instead of an NSString object. You need to figure out where and make a correction.
  • ad1269ad1269 Posts: 29New Users
    Oh thanks, I missed that. I built my app and now it doesn't crash. The only issue is that even if a message was received, the message is displayed on the right side. It never displays it on the left side no matter what.

    Thanks,
    AD
  • BrianSlickBrianSlick Posts: 9,316Tutorial Authors, Registered Users
    Are you ever changing the value of 'received' in these message objects? You aren't in the code posted above.
    ad1269
  • ad1269ad1269 Posts: 29New Users
    What would I have to change the value of received to. Would I do it in the ADMessage.m file.
    Right now my code looks like this.

    #import "ADMessage.h"

    @implementation ADMessage
    @synthesize received;
    @synthesize messageBody;

    @end

    What would I have to change?
    Post edited by ad1269 on
  • BrianSlickBrianSlick Posts: 9,316Tutorial Authors, Registered Users
    Come on, you're really not trying here. If you set the messageBody to nil, then how would you display the message? That doesn't make any sense.

    received was defined as a BOOL, which means YES or NO. That was just a suggestion, there are lots of ways to accomplish the goal, but this one is simple enough. If (isReceived == YES), then what does that mean? Means the message was incoming. If (isReceived == NO), then what does that mean? Means the message was outgoing. So you need to provide appropriate values at the proper times.

    But seriously, use your head. You need to distinguish between incoming and outgoing messages. How should you do that? Doesn't matter. How do you want to do that? What makes sense for you? You could use a BOOL as I indicated. You could use a string:
    #define kMessageStatusSent @"SENT"
    #define kMessageStatusReceived @"RECEIVED"

    @property (nonatomic, copy) NSString *messageStatus;
    You could use a number:
    typedef enum {
    MessageCodeSent = 0,
    MessageCodeReceived,
    } MessageCode

    @property (nonatomic, assign) NSInteger messageCode;
    There are lots of options. So pick something that you like, and go with that. After you make that decision, then you have to supply the corresponding value at appropriate times.
    // Received a message
    // Created a ADMessage object
    [message setReceived:YES];
    - or -
    [message setMessageStatus:kMessageStatusReceived];
    - or -
    [message setMessageCode:MessageCodeReceived];
    Then check the value later to decide what to do for different conditions.
  • ad1269ad1269 Posts: 29New Users
    Okay, but when I check the value I get an error. I think I'm not using the proper syntax. My code is below and I get the error:Unexpected type name BOOL, expected expression.

    ADMessage *cellData = [messages objectAtIndex:indexPath.row];

    NSString *msg = cellData.messageBody;

    BOOL *yesOrNo = cellData.received;

    CGSize size = [msg sizeWithFont:[UIFont systemFontOfSize:14.0] constrainedToSize:CGSizeMake(240.0f, 480.0f) lineBreakMode:UILineBreakModeWordWrap];

    UIImage *balloon; //error on this line

    if(yesOrNo == YES)
    {
    balloonView.frame = CGRectMake(0.0, 2.0, size.width + 28, size.height + 15);
    balloon = [[UIImage imageNamed:@"grey.png"] stretchableImageWithLeftCapWidth:24 topCapHeight:15];
    label.frame = CGRectMake(16, 8, size.width + 5, size.height);

    }
    </pre>

Sign In or Register to comment.