iOS网络开发-打造自己的视频客户端
一.展示实现
效果
客户端: 服务器端:
二.创建表
create table CourseVideo
(
VideoID int IDENTITY(,) NOT NULL,
CourseID int NOT NULL, VideoName varchar() NULL,
VideoPath [varchar]() NULL,
VideoImage [varchar]() NULL,
VideoDes [varchar]() NULL,
VideoLength int NULL,
primary key(VideoID)
)
添加数据
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (, , N'数组1_为什么要使用数组.mp4', N'CourseVideo/1.mp4', N'CourseImage/1.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (, , N'数组2_什么是数组', N'CourseVideo/2.mp4', N'CourseImage/2.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (, , N'数组3_数组的分类及特点', N'CourseVideo/3.mp4', N'CourseImage/3.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (, , N'数组4:一维数组的声明', N'CourseVideo/4.mp4', N'CourseImage/4.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (, , N'数组5:一维数组的初始化', N'CourseVideo/5.mp4', N'CourseImage/5.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (, , N'数组6:一维数组的访问(引用)', N'CourseVideo/6.mp4', N'CourseImage/6.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (, , N'数组7:数组的算法:查找', N'CourseVideo/7.mp4', N'CourseImage/7.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (, , N'数组8:数组的算法:排序 (1)', N'CourseVideo/8.mp4', N'CourseImage/8.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (, , N'数组09:二维数组的声明', N'CourseVideo/9.mp4', N'CourseImage/9', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (, , N'数组10:二维数组的初始化', N'CourseVideo/10.mp4', N'CourseImage/10.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (, , N'数组11:二维数组的访问', N'CourseVideo/11.mp4', N'CourseImage/11.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (, , N'数组12:多维数组简介', N'CourseVideo/12.mp4', N'CourseImage/12.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (, , N'数组13:C语言中的字符串', N'CourseVideo/13.mp4', N'CourseImage/13.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (, , N'数组14:字符数组', N'CourseVideo/14.mp4', N'CourseImage/14.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (, , N'数组15:字符串的输入输出', N'CourseVideo/15.mp4', N'CourseImage/15.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (, , N'数组16:字符串处理函数', N'CourseVideo/16.mp4', N'CourseImage/16.jpg', NULL)
GO
记得视频路径勿加中文,否则视频播放不出来
三.搭建WebService服务器
1.DatableToList.cs文件用于DataTable转换List<T>
public class DatableToList
{
public static List<T> ConvertToList<T>(DataTable dt) where T : new()
{
//定义集合
List<T> ts = new List<T>(); //获得此模型的类型
Type type = typeof(T); //定义一个临时变量
string tempName = string.Empty; //便利DataTable数据行
foreach (DataRow dr in dt.Rows)
{
T t = new T();
//获得此模型的公共属性
PropertyInfo[] propertys = t.GetType().GetProperties(); //遍历该对象的所有属性
foreach(PropertyInfo pi in propertys)
{
tempName = pi.Name;//将属性名称赋值给临时变量
//检查DataTable是否包含此列(列名==对象的属性名)
if (dt.Columns.Contains(tempName))
{
// 判断此属性是否有Setter
if (!pi.CanWrite) continue;//该属性不可写,直接跳出
//取值
object value = dr[tempName];
//如果非空,则赋给对象的属性
if (value != DBNull.Value)
pi.SetValue(t, value, null);
}
}
//对象添加到泛型集合中
ts.Add(t);
}
return ts;
} }
2.创建Model类库
CourseVideo.cs类
public class CourseVideo
{
private int videoID; public int VideoID
{
get { return videoID; }
set { videoID = value; }
}
private int courseID; public int CourseID
{
get { return courseID; }
set { courseID = value; }
}
private String videoName; public String VideoName
{
get { return videoName; }
set { videoName = value; }
}
private String videoPath; public String VideoPath
{
get { return videoPath; }
set { videoPath = value; }
}
private String videoImage; public String VideoImage
{
get { return videoImage; }
set { videoImage = value; }
}
private int videoLength;
public int VideoLength
{
get { return videoLength; }
set { videoLength = value; }
}
}
3.创建Dal类库
CourseVideoDal.cs类
查询CourseVideo表信息
这是比较简单容易理解的方式,但是字段多的话就很不实用。
//查询视频资源
public List<CourseVideo> Select()
{
List<CourseVideo> list = new List<CourseVideo>();
DataTable dt = new DataTable();
CourseVideo model = null;
DataBase db = new DataBase();
String comstr = "select VideoID,CourseID,VideoName,VideoPath,VideoImage,VideoLength from CourseVideo";
dt = db.GetDataTable(comstr);
for (int i = ; i < dt.Rows.Count;i++ )
{
model = new CourseVideo();
model.VideoID = Convert.ToInt32(dt.Rows[i][]);
model.CourseID = Convert.ToInt32(dt.Rows[i][]);
model.VideoName = dt.Rows[i][].ToString();
model.VideoPath = dt.Rows[i][].ToString();
model.VideoImage = dt.Rows[i][].ToString();
model.VideoLength = Convert.ToInt32(dt.Rows[i][5]);
list.Add(model);
}
return list;
}
之前新建的DatableToList.cs类文件就可以用到了,使用泛型将DataTable数据转换为List<T>
泛型之前一直没机会用到,于是自己百度学习了一下,封装好DatableToList文件后,很好的提高代码
了质量,更方便使用。
//使用泛型 查询视频资源
public List<CourseVideo> Select2()
{
List<CourseVideo> list = new List<CourseVideo>();
DataTable dt = new DataTable();
DataBase db = new DataBase();
String comstr = "select VideoID,CourseID,VideoName,VideoPath,VideoImage,VideoLength from CourseVideo";
dt = db.GetDataTable(comstr);
list = DatableToList.ConvertToList<CourseVideo>(dt);
return list; }
4.新建Web 服务
只需要在App_Code文件夹下找到Service.cs添加
4.1返回json格式
添加命名空间:
using System.Web.Script.Services;
using System.Web.Script.Serialization;
还有在方法前面声明
[WebMethod(Description = "json查询视频资源")]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
[WebMethod(Description = "json查询视频资源")]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public String VideoSelect()
{
return new JavaScriptSerializer().Serialize(courseVideoDal.Select());
// return dal.Select(); }
4.1返回xml格式
[WebMethod(Description = "xml查询视频资源")] public List<CourseVideo> xmlVideoSelect()
{
return courseVideoDal.Select();
}
设置外部访问需要在Web.config添加节点:
<webServices>
<protocols>
<add name="HttpSoap" />
<add name="HttpPost" />
<add name="HttpGet" />
<add name="Documentation" />
</protocols>
</webServices>
看下结果
接下来把项目部署在IIS服务器上即可使用,如何部署我这就不多说了,可以查一下百度
附件:忘记保存了,这里用到一个工具
Parse WSDL后稍等15秒左右出现Finish!查看导入目录
将生成的所有文件放置在wsdl2objc文件夹导入项目中
尝试编译出现错误如下:1."libxml/tree.h" file not found
解决办法:
链接libxml2.2dylib库
TARGETS -> Build Phases -> Linking Binary With Libraries-> libxml2.2dylib
TARGETS -> Build Settings -> Search Paths-> Header Search Paths,设置“/usr/include/libxml2”
TARGETS -> Build Phases -> Compile Sources 将Service.m,USAddition.m,NSDate+ISO8601Unparsing.m,NSDate+ISO8601Parsing.m
文件 设置不使用ARC -fno-objc-arc
手动ARC设置方法如下:
1.在Compiler Flags一列加上-fno-objc-arc就表示禁止这个.m文件的ARC
2.在Compiler Flags一列加上-fobjc-arc就表示开启这个.m文件的ARC
5.创建数据模型
lmjVideo.h文件
//视频ID
@property (assign,nonatomic) int ID; //视频名称
@property (copy,nonatomic) NSString *name; //视频长度
@property (assign,nonatomic) int length; //视频图片
@property (copy,nonatomic) NSString *image; //视频链接
@property (copy,nonatomic) NSString *url; + (instancetype)videoWithDict:(NSDictionary *)dict;
lmjVideo.m文件
+(instancetype)videoWithDict:(NSDictionary *)dict
{
lmjVideo *video = [[self alloc] init];
video.name = dict[@"VideoName"];
video.image = dict[@"VideoImage"];
video.url = dict[@"VideoPath"];
video.length = [dict[@"VideoLength"] intValue];
video.ID = [dict[@"VideoID"] intValue];
return video; // [video setValuesForKeysWithDictionary:dict]; // KVC方法使用前提: 字典中的所有key 都能在 模型属性 中找到 }
自定义cell,对cell内部数据处理的封装
lmjVideoCell.h文件
文件
@class lmjVideo;
@interface lmjVideoCell : UITableViewCell @property (nonatomic,strong) lmjVideo *video;
+ (instancetype)cellWithTableView:(UITableView *)tableView;
lmjVideoCell.m文件
#import "lmjVideoCell.h"
#import "lmjVideo.h"
#import "UIImageView+WebCache.h"
#import "UIView+Extension.h"
@interface lmjVideoCell()
@property (nonatomic,weak) UIView *driver; @end @implementation lmjVideoCell + (instancetype)cellWithTableView:(UITableView *)tableView
{
static NSString *ID = @"video";
lmjVideoCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
if (!cell)
{
cell = [[lmjVideoCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
}
return cell;
} - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) {
UIView *driver = [[UIView alloc] init];
driver.backgroundColor = [UIColor lightGrayColor];
driver.alpha = 0.2;
[self.contentView addSubview:driver];
self.driver = driver; } return self;
} - (void)setVideo:(lmjVideo *)video
{
_video = video; self.textLabel.text = video.name;
self.detailTextLabel.text = [NSString stringWithFormat:@"时长:%d分钟",video.length]; NSString *imageUrl = [NSString stringWithFormat:@"http://180.84.33.156:8882/%@",video.image];
[self.imageView setImageWithURL:[NSURL URLWithString:imageUrl] placeholderImage:[UIImage imageNamed:@"placeholder"]];
} - (void)layoutSubviews
{
[super layoutSubviews]; //调整子控件的frame
CGFloat imageX = ;
CGFloat imageY = ;
CGFloat imageH = self.height - * imageY;
CGFloat imageW = imageH * / ;
self.imageView.frame = CGRectMake(imageX, imageY, imageW, imageH); self.textLabel.x = CGRectGetMaxX(self.imageView.frame) + ; self.detailTextLabel.x = self.textLabel.x; CGFloat driverH = ;
CGFloat driverY = self.height - driverH;
CGFloat driverW = self.width;
self.driver.frame = CGRectMake(, driverY, driverW, driverH); }
分类
UIView+Extension.h文件
添加一个UIView的分类,直接修改UI控件的x值
@property (nonatomic,assign) CGFloat x;
@property (nonatomic,assign) CGFloat y;
@property (nonatomic,assign) CGFloat width;
@property (nonatomic,assign) CGFloat height;
UIView+Extension.m文件
#import "UIView+Extension.h" @implementation UIView (Extension) - (void)setX:(CGFloat)x
{
CGRect frame = self.frame;
frame.origin.x = x;
self.frame = frame;
} - (CGFloat)x
{
return self.frame.origin.x;
} - (void)setY:(CGFloat)y
{
CGRect frame = self.frame;
frame.origin.y = y;
self.frame = frame;
} - (CGFloat)y
{
return self.frame.origin.y;
} - (void)setWidth:(CGFloat)width
{
CGRect frame = self.frame;
frame.size.width = width;
self.frame = frame; } - (CGFloat)width
{
return self.frame.size.width;
} - (void)setHeight:(CGFloat)height
{
CGRect frame = self.frame;
frame.size.height = height;
self.frame = frame;
}
- (CGFloat)height
{
return self.frame.size.height;
}
@end
实现“视屏列表界面只支持竖屏方向
自定义lmjNavigationController控制器,其继承自UINavigationController
UIInterfaceOrientationMaskPortrait:竖屏(正常)
UIInterfaceOrientationMaskPortraitUpsideDown:竖屏(上下颠倒)
UIInterfaceOrientationMaskLandscapeLeft:横屏向左
UIInterfaceOrientationMaskLandscapeRight:横屏向右
UIInterfaceOrientationMaskLandscape:横屏(左右都支持)
UIInterfaceOrientationMaskAll:所有都支持
lmjNavigationViewController.m
#import "lmjNavigationViewController.h" @interface lmjNavigationViewController () @end @implementation lmjNavigationViewController //控制当前控制器支持那些方向 -(NSUInteger)supportedInterfaceOrientations
{
//竖屏
return UIInterfaceOrientationMaskPortrait;
} @end
自定义lmjMoviePlayerViewController控制器,继承MPMoviePlayerViewController
导入MediaPlayer.framework框架,lmjMoviePlayerViewController.h在添加头文件
#import <MediaPlayer/MediaPlayer.h>
lmjMoviePlayerViewController.m
#import "lmjMoviePlayerViewController.h" @interface lmjMoviePlayerViewController () @end @implementation lmjMoviePlayerViewController - (void)viewDidLoad
{
[super viewDidLoad]; // 移除程序进入后台的通知
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];
} #pragma mark - 实现这个方法来控制屏幕方向
/**
* 控制当前控制器支持哪些方向
* 返回值是UIInterfaceOrientationMask*
*/
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
@end
6.主控制器文件代码:
需要注意的是,视频播放的文件路径勿加中文,否则视频不能播放
//
// lmjViewController.m
// 橙子视频客户端
//
// Created by lmj on 15-6-24.
// Copyright (c) 2015年 lmj. All rights reserved.
// #import "lmjViewController.h"
#import "MBProgressHUD+MJ.h"
#import "lmjVideo.h"
#import "UIImageView+WebCache.h"
#import "lmjMoviePlayerViewController.h"
#import "lmjVideoCell.h"
#import "Service.h"
#define strUrl @"http://180.84.33.156:8882"
@interface lmjViewController ()
//所有视频的集合
@property (nonatomic,strong) NSArray *videos;
@end @implementation lmjViewController - (void)viewDidLoad
{
[super viewDidLoad];
[MBProgressHUD showMessage:@"正在加载视频信息..."];
NSString *result;
NSData *data;
ServiceSoap *binding = [Service ServiceSoap];
Service_VideoSelect *request = [[Service_VideoSelect alloc] init];
ServiceSoap12Response *response = [binding VideoSelectUsingParameters:request];
for(id mine in response.bodyParts){
if([mine isKindOfClass:[Service_VideoSelectResponse class]])
{
// [request release];
[MBProgressHUD hideHUD]; result = [mine VideoSelectResult];
data = [result dataUsingEncoding:NSUTF8StringEncoding];
if(data)
{
// NSLog(@"data----%@",data);
NSArray *array =[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
NSMutableArray *videos = [NSMutableArray array];
for (NSDictionary *dict in array) {
lmjVideo *video = [lmjVideo videoWithDict:dict];
[videos addObject:video];
NSLog(@"%@",video.url);
}
self.videos = videos;
[self.tableView reloadData];
}
else{
[MBProgressHUD showError:@"网络繁忙"];
} // NSLog(@"ns----%@",ns);
// NSDictionary *dict= [NSJSONSerialization JSONbjectWithData:data options:NSJSONReadingAllowFragmentS error:nil]; }
} }
#pragma mark -数据源
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.videos.count;
} -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
lmjVideoCell *cell = [lmjVideoCell cellWithTableView:tableView];
cell.video = self.videos[indexPath.row];
return cell;
} - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return ;
} -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
lmjVideo *video = self.videos[indexPath.row]; //播放视频
NSLog(@"%@",video.url);
NSString *videoUrl = [NSString stringWithFormat:@"http://180.84.33.156:8882/%@",video.url];
lmjMoviePlayerViewController *playerVc = [[lmjMoviePlayerViewController alloc] initWithContentURL:[NSURL URLWithString:videoUrl]]; [self presentMoviePlayerViewControllerAnimated:playerVc] ; //全拼播放
} @end
iOS网络开发-打造自己的视频客户端的更多相关文章
- iOS视频流开发(1)—视频基本概念
iOS视频流开发(1)-视频基本概念 手机比PC的优势除了便携外,她最重要特点就是可以快速方便的创作多媒体作品.照片分享,语音输入,视频录制,地理位置.一个成功的手机APP从产品形态上都有这其中的一项 ...
- IOS网络开发概述
概览 大部分应用程序都或多或少会牵扯到网络开发,例如说新浪微博.微信等,这些应用本身可能采用iOS开发,但是所有的数据支撑都是基于后台网络服务器的.如今,网络编程越来越普遍,孤立的应用通常是没有生命力 ...
- IOS网络开发(三)
1 飞机航班查询软件 1.1 问题 NSURLConnection是IOS提供的用于处理Http协议的网络请求的类,可以实现同步请求也可以实现异步请求,本案例使用NSURLConnection类实现一 ...
- IOS网络开发(二)
1 局域网群聊软件 1.1 问题 UDP协议将独立的数据包从一台计算机传输到另外一台计算机,但是并不保证接受方能够接收到该数据包,也不保证接收方所接收到的数据和发送方所发送的数据在内容和顺序上是完全一 ...
- IOS网络开发实战(二)
1 飞机航班查询软件 1.1 问题 NSURLConnection是IOS提供的用于处理Http协议的网络请求的类,可以实现同步请求也可以实现异步请求,本案例使用NSURLConnection类实 ...
- IOS网络开发实战(一)
1 局域网群聊软件 1.1 问题 UDP协议将独立的数据包从一台计算机传输到另外一台计算机,但是并不保证接受方能够接收到该数据包,也不保证接收方所接收到的数据和发送方所发送的数据在内容和顺序上是完 ...
- 初探iOS网络开发,数据解析。
通过大众点评平台开发来简单了解一下,oc的网络编程和数据解析(json) 首先我们需要到大大众点评开发者平台申请一个key.http://developer.dianping.com/app/tech ...
- IOS网络开发(一)
1 简易的聊天工具 1.1 问题 Socket的英文原义是孔或者插座的意思,通常也称作套接字,用于描述IP地址和端口,是一个通信链的句柄,本案例使用第三方Socket编程框架AsyncSocket框架 ...
- ios网络开发 网络状态检查
http://www.cnblogs.com/hanjun/archive/2012/12/01/2797622.html 网络连接中用到的类: 一.Reachability 1.添加 Reachab ...
随机推荐
- 从源码看Android中sqlite是怎么通过cursorwindow读DB的
更多内容在这里查看 https://ahangchen.gitbooks.io/windy-afternoon/content/ 执行query 执行SQLiteDatabase类中query系列函数 ...
- 判断进程是64bit还是32bit
#pragmaregion Includes#include<stdio.h>#include <windows.h>#pragmaendregionBOOL DoesWin ...
- ajax与算法,sql的group处理
function correctAction(){ $semester_id = $this->_getParam("semester_id"); $day = $this- ...
- android 三级菜单 BaseExpandableListAdapter
在网上搜了非常长时间.没有找到合适的Android三级菜单.所以就自己动手写了一个,主要使用了BaseExpandableList来实现,通过三个布局文件来完毕相应的菜单项,详细实现请參照下图. wa ...
- Python文件或目录操作的常用函数
◆ os.listdir(path) Return a list containing the names of the entries in the directory given by path. ...
- Deep Learning(深度学习)学习笔记整理系列之(八)
Deep Learning(深度学习)学习笔记整理系列 zouxy09@qq.com http://blog.csdn.net/zouxy09 作者:Zouxy version 1.0 2013-04 ...
- 笔记-AndroidStudio开发环境的搭建
首先当然是下载AndroidStudio,目前最新的稳定版是1.1 然后下载studio版本的sdk,如果用原装sdk,需要更新 安装的过程中会选择sdk的路径,此时如果已经解压了原装sdk,会进 ...
- BZOJ 1021: [SHOI2008]Debt 循环的债务( dp )
dp(i, j, k)表示考虑了前i种钱币(从小到大), Alice的钱数为j, Bob的钱数为k, 最小次数. 脑补一下可以发现, 只有A->B.C, B->A.C, C->A.B ...
- day2_python学习笔记_chapter4_标准类型和内建函数
1. 标准类型 Integer,Boolean, Long integer, Floating point real number, Complex number, String, List, Tup ...
- 尼康D5100使用设置及技巧,同样也适用尼康D5200
尼康D5100使用设置及技巧,同样也适用尼康D5200,希望对新手能有点帮助. 一.设置 1.优化校准:可以在menu菜单中找到它,一般使用"标准"就可以,建议将"标准& ...