MVC 设计模式

这两天认真研究了一下MVC设计模式,在iOS开发中这个算是重点中的重点了,如果对MVC模式不理解或者说不会用,那么你iOS肯定学不好,或者写不出好的东西,当然本人目前也在学习中,不过既然能看到这篇文档,说明你已经开始着手学习并且想深入研究它了,个人也是研究很久才搞懂,就写下来希望对各位有用,也能方便自己以后开发中查看,好了废话不多说,下面就来详细介绍一下MVC,并且用实例验证一下在项目开发中怎么去使用它。

相信你对 MVC 设计模式 并不陌生,只是不能完全理解其中的含义或者不能很好的使用它。

从字面意思来理解, Modal , View , Controller ,其用意在于将数据与视图分离开来------解藕。

在iOS cocoa touch 编程中, MVC机制被发挥得淋漓尽致。 MVC 示意图如下。 只有充分理解了MVC,才能在编写出优雅的iOS app。为充分理解 MVC, 相关的概念(比如: Delegate、 Protocol、 Notification 等)也要了然于胸。

MVC 约定, Model 不允许与View 打交道。 Model 是管理数据的, 当Model中的数据发生变化时,与之对应的视图应更新。 这就需要一种机制来支持。为此 iOS 框架提供了两种支持机制: Notification 和KVO (Key-Value Observing)。

  KVO 可简单理解为,为你所关注的 Key 对象注册一个监听器。 当有数据发生变化时,就会发出广播给所有的监听器。

MVC 也约定, View 不允许直接引用Modal, 它只能被Controller 所控制。 Controller 控制 View 显示什么数据。我们知道,View 所要显示的数据是来源于 Modal, View 上产生的事件 ( 比如 Touch事件)需要通知 Controller。 既然MVC 不允许直接打交道,就需要提供一种机制。

不错, iOS 确实提供了一种机制, 名曰: Delegate。 Delegate 这个词, 有人将它译为“委托”,也有人将它译为“代理”。名称上的差异没有什么,重要的是如何理解 Delegate。 Delegate设计模式的引入,就是为了解决UIView与Controller松耦合互动问题。

为便于理解, 这里截取一张来iOS MVC 示意图:

我们在详细介绍下这张图的内涵:

1.  图中,绿色的箭头表示直接引用。 对View 的直接引用体现在 IBOutlet 上。 当引用一个View 时,比如Button。 需要在ViewController

中声明一个  IBOutlet  UIButton * btn;

2. 然后,我们看View 是怎么向 Controller 通信的。对于这个,  iOS 有三种常见的模式:

设置View对应的Action Target。如设置UIButton的Touch up inside的Action Target。

设置View的Delegate,如UIAlertViewDelegate, UIActionSheetDelegate,UITextFieldDelegate等。

设置View的data source, 如UITableViewDataSource。

通过以上三种模式,View既能向Controller通信,又无需知道具体的Controller是谁,这样,View 就与Controller解耦了。

除此之外, iOS 还提供了 Action-Target 模式来让Controller 监听View 触发的事件。 View 又是如何获取数据呢? iOS提供了 Data source 的概念,其实也就是Protocol 的应用。

综上所述, 正是在iOS MVC框架的驱使下, 才需要深入理解 Delegate、Protocol等概念。

下面来看看代码中是怎么实现的,

说到MVC我们一开始都是先从Model开始,然后再编写对应的View最后在控制器中做相应的控制

一:Model

1:首先我们先创建一个模型类,用于实现模型数据的读取

头文件中创建两个模型属性,和两个模型方法,

  1. #pragma mark 模型属性
  2.  
  3. //用于存储对应的数据
  4.  
  5. @property (nonatomic, copy) NSString *name;
  6.  
  7. @property (nonatomic, copy) NSString *icon;
  8.  
  9. #pragma mark 模型方法
  10.  
  11. //用于初始化模型数据
  12.  
  13. -(instancetype)initWithDict:(NSDictionary *)dict;
  14.  
  15. +(instancetype)shopWithDict:(NSDictionary *)dict;

实现文件中实现对应的模型方法,

  1. #pragma mark 模型方法de实现
  2.  
  3. -(instancetype)initWithDict:(NSDictionary *)dict{
  4. if (self == [super init]) {
  5. //创建模型并且通过字典的键获取里面的值放到模型属性中,方便后面用于数据处理直接食用
  6. shopsModel *shop = [[shopsModel alloc] init];
  7. shop.name = dict[@"name"];
  8. shop.icon = dict[@"icon"];
  9. }
  10. return self;
  11. }
  12.  
  13. +(instancetype)shopWithDict:(NSDictionary *)dict
  14. {
  15. return [[self alloc] initWithDict:dict];
  16. }

二:View

/***********************纯代码***********************************/

创建一个视图类,用于显示对应的视图(控件,数据)

头文件中通过模型定义一个属性,并且定义三个快速创建视图View的方法,这种方法是使用较多的,而且让人一看上去就知道怎么用

  1. //引入模型类
  2. @class shopsModel;
  3.  
  4. @interface shopsView : UIView
  5.  
  6. @property (nonatomic, assign) shopsModel *shop;
  7.  
  8. //实例方法,使用模型快速创建视图View
  9. -(instancetype)initWIthShop:(shopsModel *)shop;
  10.  
  11. //类方法,使用模型快速创建视图View
  12. +(instancetype)shopWithShop:(shopsModel *)shop;
  13.  
  14. //用于创建View的一个类方法
  15. +(instancetype)shopView;

实现文件中先导入模型类:

#import "shopsModel.h"

然后实现对应的创建View的方法,

  1. -(instancetype)initWIthShop:(shopsModel *)shop
  2. {
  3. if (self == [super init]) {
  4. self.shop = shop;
  5. }
  6. return self;
  7. }
  8.  
  9. +(instancetype)shopWithShop:(shopsModel *)shop
  10. {
  11. return [[self alloc] initWIthShop:shop];
  12. }
  13.  
  14. +(instancetype)shopView
  15. {
  16. return [[self alloc] init];
  17. }

记得平时我们自定义View的时候,都是直接在init方法中做的,但是,这里有一个细节需要注意的,就是init方法内部会自动调用initWithFrame方法,我们要自定义View一般要做的就是设置View的布局和View的创建,而initWithFrame正好是控件布局之前创建控件的时候调用的,所以我们建议在这里设置他的Frame

这里我们先要在私有拓展中定义两个属性用于记录我们所创建的View的属性

  1. @property (nonatomic, weak) UIImageView *imageV;
  2.  
  3. @property (nonatomic, weak) UILabel *label;

实现空间创建的View方法

  1. //初始化View的方法
  2. -(instancetype)initWithFrame:(CGRect)frame
  3. {
  4.  
  5. if (self == [super initWithFrame:frame]) {
  6. //创建UIImageView和UILabel把它加到自定义View上面,并且使用我们定义的属性纪录他,方便后面使用
  7.  
  8. UIImageView *image = [[UIImageView alloc] init];
  9. [self addSubview:image];
  10. self.imageV = image;
  11.  
  12. UILabel *label = [[UILabel alloc] init];
  13. [self addSubview:label];
  14. self.label = label;
  15. }
  16. return self;
  17. }

在View中布局空间的时候就会调用下面的方法

  1. //布局子控件方法
  2. -(void)layoutSubviews
  3. {
  4. [super layoutSubviews];
  5.  
  6. //获取宽高
  7. CGFloat W = self.frame.size.width;
  8. CGFloat H = self.frame.size.height;
  9.  
  10. //设置自定义View中对应控件的Frame
  11. self.imageV.frame = CGRectMake(, , W, W);
  12. self.label.frame = CGRectMake(, W, W, H - W);
  13. }

我们还有一个事情要做,就是重写通过模型创建的那个属性,将模型里面的属性设置到控件中对应的属性,

  1. //重写Set方法,设置对应的数据
  2. -(void)setSpView:(shopsModel *)shop
  3. {
  4. _shop = shop;
  5.  
  6. //使用模型中的数据设置控件对应的属性
  7. self.imageV.image = [UIImage imageNamed:shop.icon];
  8. self.label.text = shop.name;
  9.  
  10. }

/***********************Xib***********************************/

关于Xib这里就不多做解释了

说一下怎么使用Xib创建一个我们自定义的View并且,在控制器里面显示

首先新建一个文件选中interface Builder中的空文件设置一个名字,就可以创建一个Xib文件

————然后创建一个自定义View的类。

点击Xib会看到里面什么也没有,因为我需要自定View所以拖一个View到Xib内部,并且拖我们对应要实现的控件到View里面作为他的子控件,这里需要注意的我们需要设置Xib文件对应的类为我们创建的那个类的名字:

然后我们要做的就是将我们放在View里面的属性设置对输出口(这里就是拖线)这里我们一般是拖到实现文件中的私有拓展中

  1. //控件输出口
  2.  
  3. @property (weak, nonatomic) IBOutlet UIImageView *icon;
  4.  
  5. @property (weak, nonatomic) IBOutlet UILabel *name;

再后面的操作之前我们还需要在头文件引入这个类,并且通过模型创建一个属性

@property (nonatomic, strong) shopsModel *shop;

定义一个通过模型快速创建View的方法

+(instancetype)shopViewWithShop:(shopsModel *)shop;

然后就是在实现文件中实现这个方法,我们是将Xib的加载封装在里面更好的实现解耦和不被外界知道

这里加载Xib文件的方式有两种

  1. /**
  2. * 便利创建自定义View的方法
  3. */
  4. +(instancetype)shopViewWithShop:(shopsModel *)shop
  5. {
  6.  
  7. /**
  8. * 加载Xib文件
  9. */
  10. iCocosView *shops = [[[NSBundle mainBundle] loadNibNamed:@"shops.plist" owner:nil options:nil] lastObject];
  11. /**
  12. * 第二种方法
  13. */
  14. // UINib *nib = [UINib nibWithNibName:@"shops.plist" bundle:[NSBundle mainBundle]];
  15. // NSArray *arr = [nib instantiateWithOwner:nil options:nil].lastObject;
  16.  
  17. shops.shop = shop;
  18. return shops;
  19. }

这里同样需要实现重写那个通过模型创建的属性的Setter方法

  1. //重写Setter方法,设置View中对应的控件的属性为模型中的数据
  2. -(void)setShop:(shopsModel *)shop
  3. {
  4. _shop = shop;
  5.  
  6. //设置模型属性
  7. self.icon.image = [UIImage imageNamed:shop.icon];
  8. self.name.text = shop.name;
  9. }

三:Controller

完成上面之后,控制器里面实现久简单多了

定义一个可变数组用于存放我们的模型数据

@property (nonatomic, strong) NSMutableArray *shops;

使用懒加载的方式加载那个plist数据,并且转成模型放到一个数组中,方便后面的使用

  1. //懒加载
  2. -(NSMutableArray *)shops
  3. {
  4. if (_shops == nil) {
  5. //加载plist数据并且把他放到一个数组中
  6. NSArray *shopsArray = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"shops.plist" ofType:nil]];
  7. //初始化存放数据的可变模型数组
  8. _shops = [NSMutableArray array];
  9.  
  10. //遍历那个存放好了plist数组的数组,把他放到一个字典中
  11. for (NSDictionary *arr in shopsArray) {
  12.  
  13. //使用快速创建模型的方法创建一个模型对象,并且将他加到可变的模型数组中,方便后面使用
  14. shopsModel *shop = [shopsModel shopWithDict:arr];
  15. [_shops addObject:shop];
  16. }
  17. }
  18. return _shops;
  19.  
  20. }

最后我们就只需要在控制器里面控制并且使用上面的模型和View了,

先来看看纯代码是怎么实现的

  1. //使用快速创建方法去存放模型数据的数组中取出数据,通过View内部的实现显示到View上面
  2. shopsView *shView = [shopsView shopWithShop:self.shops[count]];
  3. //设置View的frame
  4. shView.frame = CGRectMake(shopX, shopY, shopW, shopH);
  5. //将自定义View加到界面中显示
  6. [self.shopView addSubview:shView];

如果你使用的是Xib,方法和思路还是一样的

  1. //去存放模型数据的数组中取出数据
  2. iCocosView *shop = self.shops[index];
  3. //通过取出来的数据快速创建一个View放到view内部实现并且使用
  4. iCocosView *shopView = [iCocosView shopViewWithShop:shop];
  5. //设置View的Frame
  6. shopView.frame = CGRectMake(shopX, shopY, shopW, shopH);
  7. //将自定义的View添加到界面显示
  8. [self.shopsView addSubview:shopView];

/***********************************************Swift实现*******************************************************/

注:如果你没有一点Swift基础(基本语法都不知道,虽然和OC很相似,但看了也是没有用的),建议保留此文,后面学习的Swift过程中遇到的时候再拿来看看就完全不一样了。

最近swift被炒的很火,由于苹果今年做了一个很大的决定,就是Swift2.0将开源,9月份将会放出源码,就意味着我们可以知道这里面是怎么实现的,并且可以在Linux平台上写,我想好处远远不止这些。

笔者对swift也有些一些研究,平时在OC上面学习到一个好东西的时候都会使用实现一遍,所以这个就更不能例外了。

一:Model

第一步我们同样从模型下手,这里喝OC有些不同的是Swift只是在一个文件里面实现的

  1. import UIKit
  2.  
  3. class Shop: NSObject {
  4.  
  5. //定义变量字符串属性
  6. var name:String!
  7. var icon:String!
  8.  
  9. //初始化模型方法
  10. init(dict:[String:String]) {
  11. super.init()
  12.  
  13. //设置模型对应的属性
  14. self.name = dict["name"]
  15. self.icon = dict["icon"]
  16.  
  17. //使用封装好的方法设置模型属性
  18. setValuesForKeysWithDictionary(dict)
  19. }
  20.  
  21. }

二:View

/**************************************纯代码************************************************/

自定义View中实现的方法也是差不多的,只是方法的形式和关键字不同而已

  1. import UIKit
  2.  
  3. class ShopView: UIView {
  4.  
  5. /// 懒加载控件
  6. lazy var iconView:UIImageView = UIImageView()
  7. lazy var nameView:UILabel = UILabel()
  8.  
  9. /**
  10. 初始化Frame
  11. */
  12. override init(frame: CGRect) {
  13. super.init(frame: frame)
  14.  
  15. //添加子控件到界面
  16. self.addSubview(iconView)
  17. self.addSubview(nameView)
  18. //设置Label的文字剧中
  19. nameView.textAlignment = NSTextAlignment.Center
  20. }
  21.  
  22. /**
  23. 从文件中加载数据(Xib/StoryBoard)
  24. */
  25. required init(coder aDecoder: NSCoder) {
  26. fatalError("init(coder:) has not been implemented")
  27. }
  28.  
  29. /**
  30. 布局子控件方法
  31. */
  32. override func layoutSubviews() {
  33. //获取宽高
  34. var W:CGFloat = self.frame.size.width
  35. var H:CGFloat = self.frame.size.height
  36.  
  37. //设置UIImageView和UIlable的frame
  38. self.iconView.frame = CGRectMake(, , W, W)
  39. self.nameView.frame = CGRectMake(, W, W, H - W)
  40. }
  41. }

/**************************************Xib************************************************/

使用Xib方式同样是先创建Xib,创建对应的类文件,设置Xib对应为我们创建的类,添加子控件,设置输出口,然后就实现对应的方法

  1. import UIKit
  2.  
  3. class XMGShopView: UIView {
  4.  
  5. /** 图片 */
  6. @IBOutlet weak var iconView: UIImageView!
  7. /** 名字 */
  8. @IBOutlet weak var nameLabel: UILabel!
  9.  
  10. var shop: Shop? {
  11. didSet {
  12. // 重写set方法
  13. iconView.image = UIImage(named: shop!.icon)
  14. nameLabel.text = shop!.name
  15. }
  16. }
  17. //加载Xib实现方法
  18. class func shopView() -> XMGShopView{
  19. return NSBundle.mainBundle().loadNibNamed("XMGShopView", owner: nil, options: nil).last as! XMGShopView
  20. }
  21.  
  22. }

注:这里最值得注意的地方是didSet这个方法,其实在swift中海油一个方法叫willSet,他们是相对应的,使用来监听属性变化的,就相当于OC里面的KVO不过在这里叫做属性观察者,分别是在设置属性后和之前调用,这里由于需要只实现了设置之后观察属性的变化

三:Conreoller

关于控制器里面实现的代码和OC里面就有许多不同的地方了,特别是懒加载(lazy)这里,笔者也是搞了好久才搞明白

懒加载

  1. //使用lazy实现懒加载,这里使用的是一个叫做闭包返回值的东西来实现的
  2. lazy var shops:NSMutableArray = {
  3. //从MainBundle中获取plist文件的路径
  4. let path:String = NSBundle.mainBundle().pathForResource("shops.plist", ofType: nil)!
  5. //加载plist文件放到一个可变数组里面,
  6. let tempArr:NSMutableArray = NSMutableArray(contentsOfFile: path)!
  7. //定义一个可变的数组,数组的大小就是上面那个存放plist数据的数组的大小
  8. let shopsArrM:NSMutableArray = NSMutableArray(capacity: tempArr.count)
  9. //遍历存放plist数据的那个数组,放到一个字典中去
  10. for dict in tempArr
  11. {
  12. //使用模型中实现的方法创建一个模型对象
  13. let shop: Shop = Shop(dict: dict as! [String : String])
  14. //将模型对象放到plist数组中
  15. shopsArrM.addObject(shop)
  16. }
  17. //返回那个存放模型数据的数组
  18. return shopsArrM
  19. }()

下面就死创建并且显示View的实现

/**************************************纯代码************************************************/

  1. //创建一个自定义的View
  2. let shopView: ShopView = ShopView()
  3. //设置他的frame
  4. shopView.frame = CGRect(x: shopX, y: shopY, width: shopW, height: shopH)
  5. //取出模型数组中对应的数组设置到试图中(这里使用了?表示类型转换)
  6. shopView.shop = self.shops[index] as? Shop
  7. //添加并显示
  8. self.shopsView.addSubview(shopView)

/**************************************Xib************************************************/

  1. //创建一个自定义的View
  2. let shopView: iCocosView = iCocosView.shopView()
  3. //设置他的frame
  4. shopView.frame = CGRect(x: shopX, y: shopY, width: shopW, height: shopH)
  5. //取出模型数组中对应的数组设置到试图中(这里使用了?表示类型转换)
  6. shopView.shop = self.shops[index] as? Shop
  7. //添加并显示
  8. self.shopsView.addSubview(shopView)

使用纯代码和Xib的方式没有什么不同,最主要是自定义View内部的实现。

mvc机制

说明:

(1)在开发过程中,作为控制器处理的量级应该很轻,不该操心的不操心。协调好模型和视图就ok了,要学会当一个好老板。

(2)三个部分各司其职,数据模型只负责数据的处理,视图部分只负责把拿到的数据进行显示,两个部分都是被动的,等待着大管家控制器的调遣。

(3)在OC中,如果视图和数据模型之间有通道,那控制器是否处于失控状态呢?

网上有人是这里理解MVC的:

MVC是Model-VIew-Controller,就是模型-视图-控制器,这些都是什么东西呢?MVC把软件系统分为三个部分:Model,View。controller。在cocoa中,你的程序中的每一个object(对象)都将明显地仅属于这三部分中的一个,而完全不属于另外两个。

      Model = 你的程序是什么(而不是你的程序是如何显示的)

让我们举个例子,我们上中学的时候,我们的步步高电子词典中有个游戏叫“雷霆战机”,也就是“打飞机”的游戏,Model就是:你的小飞机的攻击力是多少?你的小飞机上装的是什么武器,炮弹,导弹,还是激光炮?你的小飞机还有多少血?等等。再概括点说,就是你的程序将要实现的功能,或者是它所能干的事情。

  

                  Controller = 如何使你的模型呈现给用户(程序逻辑)

Controller是程序内部的逻辑,大多情况下你将看不到它,它将Model和View捆绑在一起,它将处理用户的输入,例如,你按开炮的键子,Controller就会通过内部的逻辑来处理你的要求,并在屏幕上做出相应的显示,你将看到屏幕上的小飞机发出炮弹击中敌机。这也是Controller控制View的显示的例子。所以你可以把Controller看成是连接M和V的桥梁。

                  View = 在屏幕上你所看到的(是你的Controller的“奴才”)

接着前面的小飞机,View就是:你的小飞机是什么样子的,有一个还是两个翅膀,有几挺枪炮;还有,你的飞机在屏幕上的位置等等。总之,你在屏幕上看到的组件都可以归类为View。

iOS开发——MVC详解&Swift+OC的更多相关文章

  1. iOS开发-Runtime详解

    iOS开发-Runtime详解 简介 Runtime 又叫运行时,是一套底层的 C 语言 API,其为 iOS 内部的核心之一,我们平时编写的 OC 代码,底层都是基于它来实现的.比如: [recei ...

  2. iOS开发:详解Objective-C runTime

    Objective-C总Runtime的那点事儿(一)消息机制 最近在找工作,Objective-C中的Runtime是经常被问到的一个问题,几乎是面试大公司必问的一个问题.当然还有一些其他问题也几乎 ...

  3. iOS开发——Block详解

    iOS开发--Block详解 1. Block是什么 代码块 匿名函数 闭包--能够读取其他函数内部变量的函数 函数变量 实现基于指针和函数指针 实现回调的机制 Block是一个非常有特色的语法,它可 ...

  4. IOS开发之----详解在IOS后台执行

    文一 我从苹果文档中得知,一般的应用在进入后台的时候可以获取一定时间来运行相关任务,也就是说可以在后台运行一小段时间. 还有三种类型的可以运行在后以,1.音乐2.location 3.voip 文二 ...

  5. iOS开发--Bison详解连连支付集成简书

    "最近由于公司项目需要集成连连支付,文档写的不是很清楚,遇到了一些坑,因此记录一下,希望能帮到有需要的人." 前面简单的集成没有遇到什么坑,在此整理一下官方的集成文档,具体步骤如下 ...

  6. iOS开发-Runtime详解(简书)

    简介 Runtime 又叫运行时,是一套底层的 C 语言 API,其为 iOS 内部的核心之一,我们平时编写的 OC 代码,底层都是基于它来实现的.比如: [receiver message]; // ...

  7. iOS开发之详解正则表达式

    本文由Charles翻自raywenderlich原文:NSRegularExpression Tutorial: Getting Started更新提示:本教程被James Frost更新到了iOS ...

  8. iOS开发-NSURLSession详解

    Core Foundation中NSURLConnection在2003年伴随着Safari浏览器的发行,诞生的时间比较久远,iOS升级比较快,AFNetWorking在3.0版本删除了所有基于NSU ...

  9. iOS开发-UITabBarController详解

    我们在开发中经常会使用到UITabBarController来布局App应用,使用UITabBarController可以使应用看起来更加的清晰,iOS系统的闹钟程序,ipod程序都是非常好的说明和A ...

随机推荐

  1. Maven使用教程

    一.Maven介绍 我们在开发项目的过程中,会使用一些开源框架.第三方的工具等等,这些都是以jar包的方式被项目所引用,并且有些jar包还会依赖其他的jar包,我们同样需要添加到项目中,所有这些相关的 ...

  2. JMX学习一

    JMX        即 Java Management Extensions   Java管理扩展MBean   即 managed beans                         被管 ...

  3. Spring @Resource、@Autowired、@Qualifier的注解注入及区别

    spring2.5提供了基于注解(Annotation-based)的配置,我们可以通过注解的方式来完成注入依赖.在Java代码中可以使用 @Resource或者@Autowired注解方式来经行注入 ...

  4. 结构型:代理模式 Vs 适配器模式 Vs 门面模式(外观模式)

    先上UML图 代理模式: 适配器模式: 门面模式(外观模式): 打了例子……呃……举个比方 代理模式: 水浒街,西门庆看上潘金莲,想和她嘿咻嘿咻,但是自己有不能去找潘金莲去说,于是他找到了金牌代理人王 ...

  5. CXF之四 cxf集成Spring

    CXF原生支持spring,可以和Spring无缝集成.WebService框架CXF实战一在Tomcat中发布WebService(二)通过Spring Web实现CXFServlet.下面将Spr ...

  6. 初涉C#防止黑客攻击站短

    一.同一个IP如果在一分钟内连续发送5个站短可以认为是不正确的,原因有2方面: 1.发站短的页面是有点击按钮,点击按钮后马上按钮会变为不可点击,所以在前端要防止点击一次触发多次的情况 2.发送短信的U ...

  7. cocos2d-x的helloLua例子函数名定义误导初学者

    初次研究cocos2d-x, cocos2d-x支持lua是一个很不错的功能,使用lua来开发有个最大的好处就是不用每次改了游戏代码都编译,大多数情况下改了脚本直接运行程序就可以了,发布更新时也不用更 ...

  8. [Orchard CMS系列] 创建主题(Writing a new theme)

    本文需要对Orchard CMS有基本了解. 开启模块 code generation 创建新的主题工程骨架 Codegen theme MyTheme 创建主题样式 src\Orchard.Web\ ...

  9. Windows命令行使用FTP

    1.系统环境 FTP客户端:Windows7旗舰版,管理员权限命令行: FTP服务端:CentOS 6.5,VSFTP,端口 21(默认) 2.登陆FTP 在命令行下输入 ftp,出现 ftp> ...

  10. 基于Qt的P2P局域网聊天及文件传送软件设计

    基于Qt的P2P局域网聊天及文件传送软件设计 zouxy09@qq.com http://blog.csdn.net/zouxy09         这是我的<通信网络>的课程设计作业,之 ...