小程序动画从头开始_从头开始构建iPhone聊天应用程序

小程序动画从头开始

设计iPhone聊天应用

安装了4000万部iPhone的用户,如果对编写iOS应用程序不感兴趣,就必须疯了。 但你从哪儿开始呢? 大多数应用程序将通过网络连接。 那么跨越这两个项目的项目,例如聊天应用程序呢? 在本文中,我将向您展示如何使用服务器和客户端组件来构建聊天应用程序。 您可以从中学到很多有关创建iOS应用程序的知识,我保证您希望在本文结尾处编写一个。

构建应用程序始于设计解决方案。 图1显示了iOS设备(在本例中为iPhone)如何通过两个PHP页面连接到服务器的体系结构。

图1.聊天应用程序客户端/服务器架构
具有连接到数据库的add.php和messages.php页面的iPhone客户端图


这两个PHP页面add.php和messages.php都连接到数据库,分别发布和检索消息。 在我提供的代码中,数据库是MySQL,但是您可以使用DB2或您喜欢的任何其他数据库。

我使用的协议是XML。 add.php页面返回一条XML消息,该消息指出消息发布是否成功。 而messages.php页面返回发布到服务器的最新消息。

在您开始之前,我想介绍您将在这里学到的东西。

  • 数据库访问 。 我向您展示了如何使用PHP将行添加到数据库并检索它们。
  • XML编码 。 服务器代码演示了如何将消息打包为XML。
  • 构建iOS界面 。 我将为应用程序构建用户界面。
  • 查询服务器 。 Objective-C代码对message.php页面进行GET请求以获取最新的聊天消息。
  • 解析XML 。 使用iOS开发人员可用的XML解析器,您可以解析从messages.php返回的XML。
  • 显示消息 。 该应用程序使用自定义列表项来显示聊天消息。 这种方法可以使您深入了解如何自定义iOS应用程序的外观。
  • 发布消息 。 该应用程序通过add.php将数据发布到服务器,该文件将指导您完成该过程。
  • 计时器 。 计时器任务用于定期轮询messages.php以查看新的聊天项何时到达。

一个示例有很多,它应提供一套不错的工具供您开发要构建的任何类型的客户端/服务器iOS应用程序。

构建服务器

首先创建数据库。 我称我为“聊天”,但您可以随便叫什么。 您只需要确保更改PHP中的连接字符串以匹配数据库的名称即可。 清单1中显示了用于为应用程序构建单个表SQL脚本。

清单1. chat.sql
DROP TABLE IF EXISTS chatitems;
CREATE TABLE chatitems (
    id BIGINT NOT NULL PRIMARY KEY auto_increment,
    added TIMESTAMP NOT NULL,
    user VARCHAR(64) NOT NULL,
    message VARCHAR(255) NOT NULL
);

这个简单的单表数据库只有四个字段:

  • 行的ID,它只是一个自动递增的整数
  • 邮件添加的日期
  • 添加消息的用户
  • 消息本身的文本

您可以更改这些字段的大小以适应您的内容。

在生产系统中,您可能还希望具有包含名称和密码的用户表以及登录用户界面,依此类推。 对于此示例,我想使数据库保持简单,因此只有一个表。

您要构建的第一件事是清单2中的add.php脚本。

清单2. add.php
<?php
header( 'Content-type: text/xml' );
mysql_connect( 'localhost:/tmp/mysql.sock', 'root', '' );
mysql_select_db( 'chat' );
mysql_query( "INSERT INTO chatitems VALUES ( null, null, '".
    mysql_real_escape_string( $_REQUEST['user'] ).
    "', '".
    mysql_real_escape_string( $_REQUEST['message'] ).
    "')" );
?>
<success />

该脚本连接到数据库,并使用发布的usermessage字段存储message 。 这是一个简单的INSERT语句,其中的两个值都进行了转义,以说明可能会干扰SQL语法的所有错误字符,例如单引号。

为了测试添加脚本,您创建了一个test.html页面,如清单3所示,该页面仅将字段发布到add.php脚本中。

清单3. test.html
<html>
<head>
    <title>Chat Message Test Form</title>
</head>
<body>
    <form action="add.php" method="POST">
        User: <input name="user" /><br />
        Message: <input name="message" /><br />
        <input type="submit" />
    </form>
</body>
</html>

这个简单的页面只有一种形式指向add.php,具有用户和消息的两个文本字段。 然后,它具有执行帖子的“提交”按钮。

安装了test.html页面后,您可以测试add.php脚本。 在浏览器中显示测试页面的外观如图2所示 ,在“用户”字段中显示为“ jack”,在“消息”字段中显示为“ This is a test”,并具有“提交查询”按钮。

图2.消息发布测试页面
具有“用户”和“消息”字段以及“提交查询”按钮的页面的屏幕截图

在这里,您添加一些值,然后单击Submit Query按钮。 如果一切正常,您会看到类似图3的内容

图3.成功的消息发布
在浏览器中使用<success />元素查看的XML文件的屏幕截图

如果不是,您可能会得到一个PHP堆栈跟踪,通知您数据库连接失败或INSERT语句不起作用。

在消息添加脚本正常工作的情况下,是时候构建messages.php脚本了,该脚本返回消息列表。 清单4中显示了该脚本。

清单4. messages.php
<?php
header( 'Content-type: text/xml' );
mysql_connect( 'localhost:/tmp/mysql.sock', 'root', '' );
mysql_select_db( 'chat' );
if ( $_REQUEST['past'] ) {
    $result = mysql_query('SELECT * FROM chatitems WHERE id > '.
        mysql_real_escape_string( $_REQUEST['past'] ).
        ' ORDER BY added LIMIT 50');
} else {
    $result = mysql_query('SELECT * FROM chatitems ORDER BY added LIMIT 50' );    
}
?>
<chat>
<?php
while ($row = mysql_fetch_assoc($result)) {
?>
<message added="<?php echo( $row['added'] ) ?>" id="<?php echo( $row['id'] ) ?>">
    <user><?php echo( htmlentities( $row['user'] ) ) ?></user>
    <text><?php echo( htmlentities( $row['message'] ) ) ?></text>
</message>
<?php
}
mysql_free_result($result);
?>
</chat>

这个脚本有点复杂。 它所做的第一件事是将查询组合在一起。 这里有两种可能性:

  • 如果提供了past参数,则脚本仅返回指定ID以后的消息。
  • 如果未指定past参数,那么将返回所有消息。

past参数的原因是您希望客户端变得聪明。 您希望客户记住已经看到的消息,并仅请求那些已经超过的消息。 客户端逻辑非常简单,它只保留找到的最高ID,并将其作为past参数发送。 首先,它可以发送0作为值,这与完全不指定任何内容相同。

该脚本的后半部分从查询结果集中检索记录,并将其编码为XML。 如果脚本的这一部分有效,那么当您选择浏览器中的页面时,您会看到类似于图4的内容。

图4.聊天消息列表
用XML编码的简短聊天消息的屏幕截图,包括时间戳,ID,用户和消息文本

这就是服务器所需的一切。 当然,您可以添加所需的任何逻辑,额外的渠道,用户验证和登录等。 为了这个实验性聊天应用程序的目的,此脚本可以很好地工作。 现在,您可以构建将使用此服务器的iOS应用程序。

建立客户

iOS IDE称为XCode。 如果没有它,则需要从Apple Developer Site下载(请参阅参考资料 )。 最新的生产版本是XCode 3,这就是我在此处使用的屏幕截图。 有一个名为XCode 4的较新版本,该版本将用户界面编辑器集成到IDE中,但是此版本目前仍处于预览模式。

安装XCode之后,该使用New Project向导构建应用程序的时候了, 如图5所示

图5.构建一个基于视图的iPhone应用程序
所选模板选项的屏幕截图:iPhone OS>应用程序和产品> iPhone>基于视图的应用程序

最简单的应用程序类型是基于视图的应用程序。 这种应用程序使您可以将控件放置在任意位置,而将大部分UI设计留给您。 选择控件后,选择iPhone或iPad。 该选择与您要模拟的设备有关。 您可以编写代码,使其可以在iPhone或iPad上使用,或在Apple附带的其他任何i设备上使用。

单击选择之后 ,将要求您命名应用程序。 我将其命名为“ iOSChatClient”,但您可以随意命名。 在给它命名后,XCode IDE将构建核心应用程序文件。 从这里开始编译一次,然后启动它,以确保一切正常。

创建用户界面

创建应用程序后,您可以开发界面。 首先从View Controller XIB文件开始,该文件位于Resources文件夹中。 通过双击该文件夹,可以打开作为UI工具包的Interface Builder。

图6.界面布局
具有消息文本框,“发送”按钮和聊天项列表的UI的屏幕截图

图6显示了我如何布置这三个控件。 顶部是一个文本框,用于输入您要发送的消息。 该文本框的右侧是“发送”按钮。 下面是一个UITableView对象,该对象显示所有聊天项。

我可以详细介绍如何在Interface Builder中进行所有设置,但是我建议您下载项目代码并亲自使用。 随意将项目用作您自己的应用程序的模板。

创建视图控制器

用户界面就是这样。 下一个任务是回到XCode IDE,并向视图控制器类定义中添加一些成员变量,属性和方法,如清单5所示

清单5. iOSChatClientViewController.h
#import <UIKit/UIKit.h>

@interface iOSChatClientViewController : UIViewController 
                             <UITableViewDataSource,UITableViewDelegate>    {
    IBOutlet UITextField *messageText;
    IBOutlet UIButton *sendButton;
    IBOutlet UITableView *messageList;

    NSMutableData *receivedData;
    NSMutableArray *messages;
    int lastId;

    NSTimer *timer;

    NSXMLParser *chatParser;
    NSString *msgAdded;
    NSMutableString *msgUser;
    NSMutableString *msgText;
    int msgId;
    Boolean inText;
    Boolean inUser;
}

@property (nonatomic,retain) UITextField *messageText;
@property (nonatomic,retain) UIButton *sendButton;
@property (nonatomic,retain) UITableView *messageList;

- (IBAction)sendClicked:(id)sender;

@end

从顶部开始,我将UITableViewDataSource和UITableViewDelegate添加到类定义中。 此代码用于驱动消息显示。 该类中有一些方法被调用,以将数据和布局信息都馈送到表视图。

实例变量分为五个组。 顶部是对各种UI元素的对象引用,要发送的消息的文本字段,发送按钮和消息列表。

在该缓冲区下面是保存返回的XML,消息列表和最后看到的ID的缓冲区。 该lastID从零开始,但设置为您对任何消息看到的最大ID值。 然后将其作为past参数的值发送回服务器。

计时器每两秒钟触发一次,以从服务器中查找新消息。 最后一部分包括解析XML所需的所有成员变量。 它们很多,因为XML解析器是基于回调的解析器,这意味着它在类中拥有很多状态。

成员变量下面是属性和单击处理程序。 接口构建器使用它们将接口元素连接到此控制器类。 实际上,通过视图控制器中的所有这些,现在是时候回到Interface Builder,并使用连接器控件将消息文本,发送按钮和消息列表连接到其相应的属性,以及将Touch Inside事件Touch InsidesendClicked方法。

构建视图控制器代码

在不使用视图控制器头的情况下,您已经准备好深入研究项目的内容并实现视图控制器。 我将其分解为几个清单,即使它只是一个文件,因此我可以更轻松地解释每个部分。

清单6是第一部分,介绍了应用程序的启动和视图控制器的初始化。

清单6. iOSChatClientViewController.m –启动
#import "iOSChatClientViewController.h"

@implementation iOSChatClientViewController

@synthesize messageText, sendButton, messageList;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
        lastId = 0;
        chatParser = NULL;
    }
    return self;
}

- (BOOL)shouldAutorotateToInterfaceOrientation:
                                       (UIInterfaceOrientation)interfaceOrientation {
    return YES;
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

- (void)viewDidUnload {
}

- (void)dealloc {
    [super dealloc];
}

这是相当标准的iOS代码。 对于可变的系统事件,有一些回调,例如内存警告和取消分配。 在生产应用程序中,您希望优雅地处理所有这些项目,但是出于本示例应用程序的目的,我不想让事情变得过于复杂。

第一个真正的任务来做出的GET请求messages.php脚本。 清单7显示了此代码。

清单7. iOSChatClientViewController.m –获取消息
- (void)getNewMessages {
    NSString *url = [NSString stringWithFormat:
        @"http://localhost/chat/messages.php?past=%ld&t=%ld",
        lastId, time(0) ];

    NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
    [request setURL:[NSURL URLWithString:url]];
    [request setHTTPMethod:@"GET"];

    NSURLConnection *conn=[[NSURLConnection alloc] initWithRequest:request delegate:self];
    if (conn)
    {
        receivedData = [[NSMutableData data] retain];
    }
    else
    {
    }
}

- (void)connection:(NSURLConnection *)connection
  didReceiveResponse:(NSURLResponse *)response
{  
    [receivedData setLength:0];
}  

- (void)connection:(NSURLConnection *)connection 
  didReceiveData:(NSData *)data  
{  
    [receivedData appendData:data];
}  

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{  
    if (chatParser)
        [chatParser release];

    if ( messages == nil )
        messages = [[NSMutableArray alloc] init];

    chatParser = [[NSXMLParser alloc] initWithData:receivedData];
    [chatParser setDelegate:self];
    [chatParser parse];

    [receivedData release];

    [messageList reloadData];

    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:
    [self methodSignatureForSelector: @selector(timerCallback)]];
    [invocation setTarget:self];
    [invocation setSelector:@selector(timerCallback)];
    timer = [NSTimer scheduledTimerWithTimeInterval:5.0 
        invocation:invocation repeats:NO];
}

- (void)timerCallback {
    [timer release];
    [self getNewMessages];
}

该代码以getNewMessages方法开头。 此方法创建请求并通过构建NSURLConnection启动它。 它还创建保存响应数据的数据缓冲区。 三个事件处理程序didReceieveResponsedidReceiveData,connectionDidFinishLoading,均处理加载数据的各个阶段。

connectionDidFinishLoading方法最重要,因为它启动XML解析器,该解析器读取数据并挑选消息。

计时器使用此处的最终方法timerCallback启动新消息的请求。 当计时器关闭时,将getNewMessages方法,该方法再次启动该过程,最后创建一个新的计时器,该计时器在超时时再次启动消息检索过程,依此类推。

下一部分, 清单8 ,处理XML的解析。

清单8. iOSChatClientViewController.m –解析消息
- (void)parser:(NSXMLParser *)parser 
didStartElement:(NSString *)elementName 
namespaceURI:(NSString *)namespaceURI 
qualifiedName:(NSString *)qName 
attributes:(NSDictionary *)attributeDict {
    if ( [elementName isEqualToString:@"message"] ) {
        msgAdded = [[attributeDict objectForKey:@"added"] retain];
        msgId = [[attributeDict objectForKey:@"id"] intValue];
        msgUser = [[NSMutableString alloc] init];
        msgText = [[NSMutableString alloc] init];
        inUser = NO;
        inText = NO;
    }
    if ( [elementName isEqualToString:@"user"] ) {
        inUser = YES;
    }
    if ( [elementName isEqualToString:@"text"] ) {
        inText = YES;
    }
}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
    if ( inUser ) {
        [msgUser appendString:string];
    }
    if ( inText ) {
        [msgText appendString:string];
    }
}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName 
   namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
    if ( [elementName isEqualToString:@"message"] ) {
        [messages addObject:[NSDictionary dictionaryWithObjectsAndKeys:msgAdded,
            @"added",msgUser,@"user",msgText,@"text",nil]];

        lastId = msgId;

        [msgAdded release];
        [msgUser release];
        [msgText release];
    }
    if ( [elementName isEqualToString:@"user"] ) {
        inUser = NO;
    }
    if ( [elementName isEqualToString:@"text"] ) {
        inText = NO;
    }
}

知道SAX解析的任何人都应该熟悉此XML解析器。 您给它一些XML,并在打开或关闭标签,发现文本等时回叫您。 它是基于事件的解析器,而不是基于DOM的解析器。 事件解析器的优点是占用的内存少。 但是缺点是它们很难使用,因为在解析期间所有状态都需要存储在主机对象中。

该过程以所有成员变量(例如msgAddedmsgUserinUser,inText初始化为空字符串或false inText 。 然后,随着在didStartElement方法中启动每个标签,代码将查看标签名称并设置适当的inUserinText布尔值。 从那里, foundCharacters方法处理将文本数据添加到适当的字符串。 然后,当找到<message>标记的末尾时, didEndElement方法通过将已解析的消息添加到消息列表来处理标记的关闭。

现在,您需要一些代码来显示消息。 如清单9所示。

清单9. iOSChatClientViewController.m –显示消息
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)myTableView numberOfRowsInSection:
                                       (NSInteger)section {
    return ( messages == nil ) ? 0 : [messages count];
}


- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:
                                       (NSIndexPath *)indexPath {
    return 75;
}

- (UITableViewCell *)tableView:(UITableView *)myTableView 
   cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = (UITableViewCell *)[self.messageList 
        dequeueReusableCellWithIdentifier:@"ChatListItem"];
    if (cell == nil) {
        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"ChatListItem" 
            owner:self options:nil];
        cell = (UITableViewCell *)[nib objectAtIndex:0];
    }

    NSDictionary *itemAtIndex = (NSDictionary *)[messages objectAtIndex:indexPath.row];
    UILabel *textLabel = (UILabel *)[cell viewWithTag:1];
    textLabel.text = [itemAtIndex objectForKey:@"text"];
    UILabel *userLabel = (UILabel *)[cell viewWithTag:2];
    userLabel.text = [itemAtIndex objectForKey:@"user"];

    return cell;
}

这些是UITableViewDataSourceUITableViewDelegate接口定义的所有方法。 最重要的一个是cellForRowAtIndexPath方法,该方法为列表项创建一个自定义UI,并将其文本字段设置为该消息的适当文本。

此自定义列表项在需要在Resources文件夹中创建的新ChatListItem.xib文件中定义。 在该文件中,创建一个新的UITableViewCell项,该项中有两个标签,分别标记为1和2。该文件以及所有其他代码在可下载项目中可用(请参见下载 )。

cellForRowAtIndexPath方法中的代码分配这些ChatListItem单元格之一,然后将标签的文本字段设置为我们为该消息找到的文本和用户值。

我知道需要接受很多工作,但是您快要结束了。 您已经具有启动视图,获取消息XML,对其进行解析并显示消息的代码。 剩下的唯一事情就是编写发送消息的代码。

构建该代码的第一部分是为用户名创建一个设置。 iOS应用程序可以定义“设置”控制面板中的自定义设置。 要创建设置,您需要使用“新建文件”向导在“资源”文件夹中创建设置包。 然后,使用图7中的设置编辑器将其删除为单个设置。

图7.设置设置
设置编辑器的屏幕截图

然后,您定义要将该设置命名为User并具有键user_preference 。 从那里,您可以使用此首选项获取清单10中消息发送代码的用户名。

清单10. iOSChatClientViewController.m –发送消息
- (IBAction)sendClicked:(id)sender {
    [messageText resignFirstResponder];
    if ( [messageText.text length] > 0 ) {
        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

        NSString *url = [NSString stringWithFormat:
            @"http://localhost/chat/add.php"];

        NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] 
            init] autorelease];
        [request setURL:[NSURL URLWithString:url]];
        [request setHTTPMethod:@"POST"];

        NSMutableData *body = [NSMutableData data];
        [body appendData:[[NSString stringWithFormat:@"user=%@&message=%@", 
             [defaults stringForKey:@"user_preference"], 
             messageText.text] dataUsingEncoding:NSUTF8StringEncoding]];
        [request setHTTPBody:body];

        NSHTTPURLResponse *response = nil;
        NSError *error = [[[NSError alloc] init] autorelease];
        [NSURLConnection sendSynchronousRequest:request 
            returningResponse:&response error:&error];

        [self getNewMessages];
    }

    messageText.text = @"";
}

- (void)viewDidLoad {
        [super viewDidLoad];

    messageList.dataSource = self;
    messageList.delegate = self;

    [self getNewMessages];
}

@end

这是“发送消息”按钮的单击处理程序代码。 它创建一个NSMutableURLRequest ,其中包含add.php脚本的URL。 然后,它将消息的主体设置为一个字符串,该字符串具有以POST格式编码的用户和消息数据。 然后,它使用NSURLConnection将消息数据同步发送到服务器,并使用getNewMessages开始消息检索。

该文件底部的viewDidLoad方法是视图加载时所调用的方法。 它启动消息检索过程,并将消息列表与此对象连接,以便消息列表知道从何处获取其数据。

有了所有这些编码之后,就可以对应用程序进行测试了。 首先在图8的“设置”页面中设置用户名。

图8.设置页面
具有“常规”,“ Safari”,“照片”和“ iOSChatClient”选项的“设置”页面的屏幕截图

从这里,单击iOSChatClient应用程序,然后显示图9中的设置页面。

图9.设置用户名
iOSChatClient设置页面的屏幕截图,其中“用户”字段中的值为“ Megan”

然后,您将像在电话上一样返回到该应用程序,并使用键盘输入一条消息, 如图10所示

图10.键入新消息
QWERTY键盘,消息文本框,发送按钮和来自用户插Kong的测试消息的屏幕截图

然后按下send按钮,我们看到消息已发送到服务器,已经过发布,然后从messages.php返回, 如图11所示

图11.完成的聊天应用程序
消息文本框,“发送”按钮以及来自用户jack和megan的两条测试消息的屏幕截图

您会从代码中注意到,发送按钮和消息列表之间没有直接连接。 因此,将消息放入列表的唯一方法是通过服务器将数据成功插入数据库中。 然后message.php代码成功返回了要显示在消息列表中的消息。

结论

当然要花很多钱,但是您从本文中学到了很多。 您在后端使用XML进行了一些数据库工作。 您使用自定义用户界面构建了一个iOS应用程序,该用户界面可以从服务器发送和检索数据。 您使用XML解析器从服务器获取响应XML。 然后,您构建了一个自定义列表UI,以使消息看起来更漂亮。

您下一步要去哪里,这取决于您。 Apple为您提供了在iPhone或iPad上实现所需视觉效果的工具。 并且本文为您提供了构建自己的支持网络的应用程序的路线图。 我鼓励您尝试一下。 如果您确实制作了一些很棒的东西,请告诉我,我一定会在App Store上进行检查。


翻译自: https://www.ibm.com/developerworks/xml/library/x-ioschat/index.html

小程序动画从头开始

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值