商城购物系统

商城购物系统

完成一个商城购物车的程序

要求:
1,用户先给自己的账户充钱:比如先充5000元。
2,有如下的一个格式:
goods = [
{“name”: “笔记本”, “price”: 15000},
{“name”: “手机”, “price”: 10000},
{“name”: “服务”, “price”: 1999},
{“name”: “美女”, “price”: 998},
]
3,页面显示 序号 + 商品名称 + 商品价格,如:
1 美女 998
2 服务 1999

4,用户输入选择的商品序号,然后打印商品名称及商品价格,并将此商品,添加到购物车(自己定义购物车),用户还可继续添加商品。
5,如果用户输入的商品序号有误,则提示输入有误,并重新输入。
6,用户输入N为购物车结算,依次显示用户购物车里面的商品,数量及单价,若充值的钱数不足,则让用户删除某商品,直至可以购买,若充值的钱数充足,则可以直接购买。
7,用户输入Q或者q退出程序。
8,退出程序之后,依次显示用户购买的商品,数量,单价,以及此次共消费多少钱,账户余额多少,并将购买信息显示。

goods = [
{“name”: “笔记本”, “price”: 15000},
{“name”: “手机”, “price”: 10000},
{“name”: “服务”, “price”: 1999},
{“name”: “美女”, “price”: 998},
]
wallet = 0 # 钱包
shopping_cart1 = [] # 购物车
while True:
print(“Welcome!”.center(50, “-“))
chose = input(“请选择模式 q/Q:退出程序 , 1:顾客模式 \n>>>”) # 模式选择
if chose.upper() == “Q”:
break
elif chose == “1”:
flag = True # 用来控着循环的正常结束,直接执行else后边的内容
print(f”您当前的账户余额为:{wallet}元.”)
while flag:
chose_2 = input(“请选择 Q/q:退出程序,1:充钱, 2:查看商品并加入购物车 \n>>>”)
if chose_2.upper() == “Q”:
flag = False
elif chose_2 == “1”:
while True:
money = input(“请输入充值金额(Q/q 退出)”)
if money.isdecimal() and int(money) > 0: # 输入正整数 不能有其他的字符
wallet += int(money)
print(f”您当前的账户余额为:{wallet}元.”)
break # 充值结束退出充值
elif money.upper() == “Q”:
break # 用户决定退出
else:
print(“你输入的格式有误请重新输入!”)
elif chose_2 == “2”:
shopping_cart = [] # 用一个列表来接受每次的购物信息里面的每个元素都是字典每个字典都包含 name price number
while True:
for i in range(len(goods)): # 展示现有的商品
print(i + 1, goods[i][“name”], goods[i][“price”])
choose = input(“请选择商品的序号:(输入N或n去结算)\n>>>”)
if choose.upper() != “N”:
if choose.isdecimal() and 0 < int(choose) < len(goods) + 1: # 判断合法输入商品的序号
print(goods[int(choose) – 1][“name”], goods[int(choose) – 1][“price”]) # 打印选择的商品
count1 = 0
for i in range(len(shopping_cart)): # 往购物车添加
if shopping_cart[i][“name”] == goods[int(choose) – 1][“name”]: # 判断是不是已经有了此商品
count1 = 1
shopping_cart[i][“number”] += 1 # 找到商品 数量+1
# print(shopping_cart)
if count1 == 0: # 没有在购物车里找到这个商品 ,直接添加到购物车
shopping_cart.append({“name”: goods[int(choose) – 1][“name”],
“price”: goods[int(choose)-1][“price”], “number”: 1})
print(shopping_cart)
print(“*” * 50)
else:
print(“请输入正确的序号!”)
else:
if len(shopping_cart) != 0: # 判断购物车是否为空

money_sum = 0
print(“我的购物车”.center(20, “*”))
print(“商品 数量 单价”)
for i in shopping_cart: # 打印购物车
print(f'{i[“name”]} {i[“number”]} {i[“price”]}’)
money_sum += i[“price”] * i[“number”] # 计算花销
print(f”您的购物车总花费为: {money_sum}元”)
print(f”您当前的账户余额为:{wallet}元.”)
if money_sum > wallet: # 判断余额是否够
while True: # 余额不足需要删除购物车的商品直至可以购买为止
print(“您的余额不足!”)
print(“我的购物车”.center(20, “*”))
print(“序号 商品 数量 单价”)
for i in range(len(shopping_cart)): # 打印购物车的商品按照序号删除
print(f'{i+1} {shopping_cart[i][“name”]} {shopping_cart[i][“number”]}’
f’ {shopping_cart[i][“price”]}’)
num_1 = input(“请选择您要删除的商品序号”)
if num_1.isdecimal() and 0 < int(num_1) <= len(shopping_cart):
shopping_cart[int(num_1)-1][“number”] -= 1
money_sum -= shopping_cart[int(num_1) – 1][“price”]
if shopping_cart[int(num_1)-1][“number”] == 0: # 如果商品只有一个则直接删除
shopping_cart.pop(int(num_1)-1)
if money_sum <= wallet:
break
else:
print(f”您的购物车总花费为: {money_sum}元”)
print(f”您当前的账户余额为:{wallet}元.余额不足!”)
else:
print(“请输入正确的格式!”)
if len(shopping_cart) != 0: # 结算—判断购物车是否为空
print(“购买成功!”.center(20,”*”))
print(“下面是你购买的物品”.center(20))
print(“商品 数量 单价”)
for i in range(len(shopping_cart)):
print(f'{shopping_cart[i][“name”]} ‘
f’ {shopping_cart[i][“number”]} ‘
f'{shopping_cart[i][“price”]}’)
print(f”您此次总消费为: {money_sum}元”)
wallet -= money_sum # 计算余额
print(f”您当前的账户余额为:{wallet}元.”)
shopping_cart1 += shopping_cart # 将此次的购物信息添加到今天的购物车信息里
else:
print(“您的购物车是空的”)
else :
print(“你的购物车是空的!”)
break
else:
print(“输入格式有误,请重新选择”)
else:
cart = [] # 整理后的购物车 包含所有的商品
for i in shopping_cart1:
count2 = 0
for j in range(len(cart)):
if i[“name”] == cart[j][“name”]:
cart[j][“number”] += i[“number”]
count2 = 1
if count2 == 0:
cart.append(i)

if len(cart) != 0: # 显示所有的购物信息 花销 以及账户余额
gw_money = 0
print(“今天购买的所有商品如下”.center(20, “*”))
print(“序号 商品 数量 单价”)
for i in range(len(cart)):
print(f'{i + 1} {cart[i][“name”]} {cart[i][“number”]} {cart[i][“price”]}’)
gw_money += cart[i][“price”] * cart[i][“number”]
print(f”您今天的总花销为{gw_money}元”)
print(f”您当前的账户余额为:{wallet}元.”)
else:
print(“您今天什么也没买!”)
break
else:
print(“输入格式有误,请重新选择”)

云计算发展进程中的六大关键技术

云计算是以数据为中心的一种数据密集型的超级计算。在数据存储、数据管理、编程模式、并发控制、系统管理等方面具有自身独特的技术。

海量分布式存储技术

为保证高可用、高可靠和经济性,云计算采用分布式存储的方式来存储数据和冗余存储的方式来保证存储数据的可靠性,从而提供廉价可靠的系统。为了满足大量用户的需求,数据存储技术必须具有高吞吐率和高传输率的特点。

云计算的数据存储系统主要有Google GFS(Google File System)和Hadoop开发团队的开源系统HDFS(Hadop Distributed File System)。大部分IT厂商,包括Yahoo、Intel的“云”计划采用的都是HDFS的数据存储技术。

并行编程模式

为了高效地利用云计算的资源,使用户能更轻松地享受云计算带来的服务,云计算的变成哦是必须保证后台复杂的并行执行和任务调度向用户和编程人员透明。云计算采用MapReduce编程模式,将任务自动分成多个子任务,通过Map和Reduce两部实现任务在大规模计算节点中的调度与分配。

数据管理技术

云计算系统对大数据集进行处理、分析,向用户提供高效的服务。因此,数据管理技术必须能够高效地管理大数据集。其次,如何在规模巨大的数据中找到特定的数据,也是云计算数据管理技术所必须解决的问题。云系统的数据管理往往采用列存储的数据管理模式,保证海量数据存储和分析性能。云计算的数据管理技术*著名的是Googe的BigTable数据管理技术,同事Hadop开发团队开发了累死BigTable的开源数据管理模块HBase。

分布式资源管理技术

在多节点并发执行环境,分布式资源管理系统是保证系统状态正确性的关键技术。系统状态需要在多节点之间同步,关键节点出现故障时需要迁移服务,分布式资源管理技术通过锁机制协调多任务对于资源的使用,从而保证数据操作的一致性。Google的Ghubby是*锥你给的分布式资源管理系统。

云计算平台管理技术

云计算资源规模庞大,一个系统的服务器数量可能会高达十万台并跨越几个坐落于不同物理地点的数据中心,同时还运行成百上千种应用。如何有效地管理这些服务器,保证这些服务器组成的系统能提供7*24小时不间断服务是一个巨大的挑战。云计算系统管理技术是云计算的“神经网络”,通过这些技术能够是大量的服务器协同工作,方便地进行业务部署和开通,快速发现和恢复系统故障,通过自动化、智能化的手段实现大会磨系统的可运营、可管理。Google通过其卓越的云计算管理系统维持着全球上百万台PC服务器协同、高效地运行,起云计算系统管理技术也被作为企业核心机密,至今没有公布任何技术资料。

绿色节能技术

云计算技术降低了服务器的采购成本,从而使电源消耗所带来的运营成本成为云计算计算中心的主要开支之一,为了进一步降低成本,云计算的先去在绿色节能技术上进行了大量探索。

传统数据中心空调冷却的费用约占整体电费的30%—70%,Google为了节省能源,在比利时的数据中心降温系统无需冷却剂,而是采取额室外空气进行自然冷却。根据比利时的气候条件,每年只有7天左右无法使用自由冷却方式。在比较炎热的夏天,Google可以通过云计算管理系统将该数据中心的计算任务转移到其他数据中心中。

日常代码工具(快速索引)

日常代码工具(快速索引)

Go for it!
1. 机器学习
1.1 Pytorch
1.1.1 分类器训练函数
1.1.2 分类器测试函数
1.1.3 通用训练组件
1.2 numpy
1.2.1 匈牙利算法进行目标追踪(bbox中心点距离作为特征)
1.3 结果评估
1.3.1 Confusion Matrix
1. 机器学习
1.1 Pytorch
1.1.1 分类器训练函数
from tqdm import tqdm

def train(model, device, epoch, train_loader, optimizer, loss_func):
model.train().to(device)
train_loss = 0
for batch_idx, (data, target) in enumerate(tqdm(train_loader, ascii = True)):
data, target = data.to(device), target.to(device).long()
optimizer.zero_grad()
output = model(data)
loss = loss_func(output, target)
loss.backward()
optimizer.step()
train_loss += loss.item()

print(“Train epoch {}, loss:{:.4f}, “.format(epoch, train_loss))

1.1.2 分类器测试函数
from tqdm import tqdm

def test(model, device, test_loader):
model.eval().to(device)
count = 0
for batch_idx, (data, target) in enumerate(tqdm(test_loader, ascii = True)):
data, target = data.to(device), target.to(device)
output = model(data)
_, label = torch.max(output, dim=-1)
count += (label == target).sum()

print(“Acc:{:.4f}”.format(count.item()*100.0/len(test_loader.dataset)))

1.1.3 通用训练组件
from torch.utils.data import Dataset, DataLoader
import torch
import torch.nn as nn

def main():
batch_size = 70
learning_rate = 0.001
epoch_num = 100
labels = [‘A’,’B’,’C’,’D’]

dataset = Mydataset(is_train = True)
test_dataset = Mydataset(is_train = False)

train_loader = DataLoader(dataset,batch_size=batch_size,shuffle = True)
test_loader = DataLoader(test_dataset,batch_size=batch_size,shuffle = False)
model = MODEL()

if os.path.exists(‘./model.pkl’):
model.load_state_dict(torch.load(‘./model.pkl’,map_location = device)[‘weights’])
print(“load model sucessfully”)

adam = torch.optim.Adam(model.parameters(), lr=learning_rate)
scheduler = torch.optim.lr_scheduler.StepLR(adam, step_size=2, gamma=0.9)

loss_func = nn.CrossEntropyLoss()

for epoch in range(1, epoch_num+1):
test(model,device,test_loader)
train(model, device,train_loader,adam,loss_func,epoch,output_dim)
scheduler.step()
model_dict = {
“labels”:labels,
‘weights’:model.state_dict(),
}
torch.save(model_dict, “model.pkl”)

1.2 numpy
1.2.1 匈牙利算法进行目标追踪(bbox中心点距离作为特征)
import numpy as np
from scipy.optimize import linear_sum_assignment

class IDcomput(object):
def __init__(self):
self.features = []

def getdistance(self, x, y):
”’
input:
x: array(n, 2)
y: array(m, 2)

output:
array(n, m)
”’
x = x[:,np.newaxis,:]
y = y[np.newaxis,:,:]

x = np.repeat(x, y.shape[0], axis = 1)
y = np.repeat(y, x.shape[1], axis = 0)
dis = (x-y)**2

dis = np.sqrt(dis[:,:,0]+dis[:,:,1])
return dis

def __call__(self, X):
”’
input:
X: array(n, 2) current bbox array eg. [num of bbox, center_xy]
output:
array(n) current id of bbox eg. [id of bbox]
”’
if len(self.features) == 0:
self.features = X
return np.array([i for i in range(len(X))])

elif len(self.features) == len(X):
dis = self.getdistance(self.features, X)
feature_ids = linear_sum_assignment(dis)
feature_ids = feature_ids[1]

elif len(self.features) < len(X):
dis = self.getdistance(self.features, X)
feature_ids = linear_sum_assignment(dis)
feature_ids = feature_ids[1]
feature_ids_rest = set([i for i in range(len(X))]).difference(set(feature_ids))
feature_ids = np.array(list(feature_ids) + list(feature_ids_rest))
temp_feat = X
temp_feat[0:len(self.features)] = self.features
self.features = temp_feat
else:
dis = self.getdistance(X, self.features)
ids = linear_sum_assignment(dis)
ids = ids[1]
self.features[ids] = X
return ids

feature_ids = feature_ids.argsort()
ids = np.array([i for i in range(len(X))])
ids = ids[feature_ids]
self.features[ids] = X

return ids

if __name__ == ‘__main__’:
idcomput = IDcomput()
x = np.array([[1,2],[0,1]])
y = np.array([[0,1], [3,2], [1,2]])
z = np.array([[0,1], [3,2]])

print(‘x’, idcomput(x))
print(‘y’,idcomput(y))
print(‘z’,idcomput(z))

1.3 结果评估
1.3.1 Confusion Matrix
import os
from sklearn.metrics import confusion_matrix
import matplotlib.pyplot as plt
import numpy as np

def plot_confusion_matrix(cm, labels_name, title,rotation=45, cmap = plt.cm.Wistia,fontsize=11):
cm = cm.astype(‘float’) / cm.sum(axis=1)[:,np.newaxis]
# plt.figure(figsize=(8,8.5))
plt.imshow(cm, interpolation=’nearest’,cmap = cmap) # ,cmap = plt.cm.Oranges cmap = plt.cm.Wistia
plt.title(title)
plt.colorbar()
num_local = np.array(range(len(labels_name)))
plt.xticks(num_local, labels_name,rotation = rotation)
plt.yticks(num_local, labels_name)

plt.ylabel(‘True label’)
plt.xlabel(“Predicted label”)
plt.subplots_adjust(bottom=0.15)

x, y = np.meshgrid(num_local, num_local)
for x_val, y_val in zip(x.flatten(),y.flatten()):
c = cm[y_val][x_val]
if c>0.01:
plt.text(x_val,y_val,”{:.2f}”.format(c),fontsize=fontsize,va=’center’,ha=’center’)

def autodraw_cm(y_true, y_pred, labels_name, save_path=”./ResNet18_cm.png”, title=”ResNet18_cm”,**kwargs):
cm = confusion_matrix(y_true,y_pred)
# print(cm)
plot_confusion_matrix(cm, labels_name,title, **kwargs)
plt.savefig(save_path)
plt.cla()
plt.clf()

if __name__ == ‘__main__’:
y_true = [1, 0]
y_pred = [1, 1]
labels_name = [‘a’,’b’]
autodraw_cm(y_true,y_pred,labels_name)

用python提取字符串中的数字

用python提取字符串中的数字

# 1. 总体思路

## 1.1. 获取一个字符串 from_string

## 1.2. 取出 from_string 的*个数字

### 1.2.1. 遍历 from_string ,找到*个数字

### 1.2.2. 存到 get_numbers 列表中

### 1.2.3. 计算出*个数字在 from_string 的位置 start_num

## 1.3. 从*个数字处开始,遍历 from_string

### 1.3.1. 从*个数字处开始对 from_string 切片,前面的丢弃

### 1.3.2. 遍历切片后的 from_string

### 1.3.3. 验证一个,符合,就往 get_numbers 里添加

### 1.3.4. 如果验证不符合,就终止循环,不用再往后验证了

## 4. 将得到的结果(列表)转化为数字

 

# 2.代码展示

from_string = input(“请输入:”)
check_start = [‘0′,’1′,’2′,’3′,’4′,’5′,’6′,’7′,’8′,’9’]
check_end = check_start + [‘.’]
from_string = list(from_string)
start_num = 0
get_numbers = []
print(from_string)

# 取出输入列表里*个数字,暂存到 get_numbers
# 并计算*个数字的位置
for i in from_string :
if i in check_start :
get_numbers.append(i)
break
start_num = start_num + 1

# get_numbers
from_string = from_string[start_num + 1:]

for i in from_string :
if i in check_end :
get_numbers.append(i)
else :
break

print(get_numbers)
get_numbers = ”.join(get_numbers)
get_numbers = float(get_numbers)
print(get_numbers)

torchtext 使用案例

torchtext 使用案例

构造数据集

root = ‘dataset/Long-document-dataset/csv/’
cls_map = {n:i for i,n in enumerate(os.listdir(root))}
print(cls_map)
corpus = []
for P in os.listdir(root):
p = root+P+’/’+P+’/’
print(p)
for fp in os.listdir(p):
with open(p+fp) as f:
text = ‘ ‘.join(f.readlines())
corpus.append([text,[cls_map[P]]])
random.shuffle(corpus)
构造Field、Dataset、Iterator

from torchtext.vocab import GloVe
from torchtext.data import Example, BucketIterator, Iterator

tokenize = lambda x: x.split()
MAX_LEN = 100
TEXT = data.Field(sequential=True, tokenize=tokenize, lower=True, fix_length=100)
LABEL = data.Field(sequential=False, use_vocab=False)

class MyDataset(data.Dataset):
def __init__(self, csv_data, text_field, label_field, test=False, aug=False, **kwargs):

# csv_data = pd.read_csv(csv_path) #其实是list:[[text,labeb], …]
fields = [(“id”, None),(“text”, text_field), (“label”, label_field)]

examples = []
for text in csv_data:
# examples.append(data.Example.fromlist([None, text[0][:MAX_LEN], text[1] if not test else None], fields))
examples.append(data.Example.fromlist([None, text[0][:1000], text[1]], fields))

# 上面是一些预处理操作,此处调用super调用父类构造方法,产生标准Dataset
# super(MyDataset, self).__init__(examples, fields, **kwargs)
super(MyDataset, self).__init__(examples, fields)

def shuffle(self, text):
# 序列随机排序
text = np.random.permutation(text.strip().split())
return ‘ ‘.join(text)

def dropout(self, text, p=0.5):
# 随机删除一些文本
text = text.strip().split()
len_ = len(text)
indexs = np.random.choice(len_, int(len_ * p))
for i in indexs:
text[i] = ”
return ‘ ‘.join(text)

def data_iter(TEXT, LABEL):

train = MyDataset(corpus[:20000], text_field=TEXT, label_field=LABEL, test=False, aug=1)
test = MyDataset(corpus[20000:], text_field=TEXT, label_field=LABEL, test=True, aug=1)#label_field=None
# 传入用于构建词表的数据集
# TEXT = data.Field(sequential=True, tokenize=tokenize, lower=True, fix_length=200)
vectors = Vectors(name=’/home1/lihaoyuan/data/NLP/glove/glove.6B.100d.txt’, cache=’.vector_cache’)
TEXT.build_vocab(train, vectors=vectors)
# TEXT.build_vocab(train, vectors=GloVe(name=’6B’, dim=300)) # TEXT.build_vocab(train, vectors=”glove.6B.200d”)
weight_matrix = TEXT.vocab.vectors
print(weight_matrix.shape)
# 只针对训练集构造迭代器
# train_iter = data.BucketIterator(dataset=train, batch_size=8, shuffle=True, sort_within_batch=False, repeat=False)

# 同时对训练集和验证集构造迭代器
# train_iter, val_iter = data.BucketIterator.splits(
# (train, valid),
# batch_sizes=(8, 8),
# # 如果使用gpu,此处将-1更换为GPU的编号
# device=-1,
# # 用来排序的指标
# sort_key=lambda x: len(x.text),
# sort_within_batch=False,
# repeat=False
# )
train_iter = Iterator(train, batch_size=64, device=torch.device(‘cuda:0’), sort=False, sort_within_batch=False, repeat=False)
test_iter = Iterator(test, batch_size=64, device=torch.device(‘cuda:0’), sort=False, sort_within_batch=False, repeat=False)
return train_iter, test_iter, weight_matrix

train_iter, test_iter, weight_matrix = data_iter(TEXT, LABEL)
分类模型

class RNN(nn.Module):

def __init__(self):
super(RNN, self).__init__()
self.word_embeddings = nn.Embedding(len(TEXT.vocab), 100) # embedding之后的shape: torch.Size([b, 100, 100])
self.word_embeddings.weight.data.copy_(weight_matrix)
self.lstm = nn.LSTM(input_size=100, hidden_size=128, bidirectional=True, num_layers=1) # torch.Size([b, 100, 128])
self.decoder = nn.Linear(256, 8)

def forward(self, sentence):
embeds = self.word_embeddings(sentence)
lstm_out = self.lstm(embeds)[0]
# final = lstm_out[-1] # 取*后一个时间步
final = lstm_out.mean(0) # 平均
y = self.decoder(final)
return y

acc_ = []
def main():
model = RNN().cuda()
model.train()
optimizer = optim.Adam(filter(lambda p: p.requires_grad, model.parameters()), lr=0.001)
loss_funtion = F.cross_entropy

for epoch in range(10):
for i, batch in enumerate(train_iter):
optimizer.zero_grad()
predicted = model(batch.text)

loss = loss_funtion(predicted, batch.label.view(-1))
loss.backward()
optimizer.step()

acc = (predicted.argmax(1) == batch.label.view(-1)).sum().float() / batch.label.size(0)
acc_.append(acc.item())

print(‘epoch:%d loss:%.3f acc:%.3f’%(epoch+1, loss.item(), np.mean(acc_)))

model.eval()
acc_test = []
for i, batch in enumerate(test_iter):
predicted = model(batch.text).argmax(1)
acc = (predicted == batch.label.view(-1)).sum().float() / batch.label.size(0)
acc_test.append(acc.item())
print(np.mean(acc_test))

if __name__ == ‘__main__’:
main()
参考:

官方文档:https://torchtext.readthedocs.io/en/latest/vocab.html?highlight=vocab

https://blog.csdn.net/nlpuser/article/details/88067167

https://www.cnblogs.com/linzhenyu/p/13277552.html

ios基本语法介绍(下篇)

Objectve-C语法总结<2>

大纲

  • 26.Protocol-协议
  • 27.delegate-代理
  • 28.Foundation框架介绍
  • 29.NSString和NSMutableString
  • 30.NSArray和NSMutableArray
  • 31.NSDictionary和NSMutableDictionary
  • 32.copy
  • 33.常见的结构体
    1. NSFileManager
  • 35.其他

书接上篇,继续来说说这个古老而又现代的开发语言。在Objectve-C语法总结<1> 那篇中OC大部分的语法基本上已经总结完毕。本篇在上一篇的基础上对语法进行少量的补充,其次主要对OC中的常用类API的介绍。

26.Protocol-协议

26.1.protocol 概念

  • Protocol翻译过来叫做”协议”
    • 在写java的时候都会有接口interface这个概念,接口就是一堆方法的声明没有实现,而在OC里面Interface是一个类的头文件的声明,并不是真正意义上的接口的意思,在OC中接口是由一个叫做协议的protocol来实现的
    • protocol它可以声明一些必须实现的方法和选择实现 的方法。这个和java是完全不同的
  • Protocol的作用
    • 用来声明一些方法
    • 也就说, 一个Protocol是由一系列的方法声明组成的

26.2.protocol 语法格式

  • Protocol的定义
    1. @protocol 协议名称
    2. // 方法声明列表
    3. @end
  • 类遵守协议
    • 一个类可以遵守1个或多个协议
    • 任何类只要遵守了Protocol,就相当于拥有了Protocol的所有方法声明
      1. @interface 类名 : 父类 <协议名称1, 协议名称2,…>
      2. @end
  • 示例
  1. @protocol SportProtocol <NSObject>
  2. – (void)playFootball;
  3. – (void)playBasketball;
  4. @end
  5. #import “SportProtocol.h” // 导入协议
  6. @interface Studnet : NSObject<SportProtocol> // 遵守协议
  7. @end
  8. @implementation Student
  9. // 实现协议方法
  10. – (void)playBasketball
  11. {
  12. NSLog(@”%s”, __func__);
  13. }
  14. // 实现协议方法
  15. – (void)playFootball
  16. {
  17. NSLog(@”%s”, __func__);
  18. }
  19. @end

26.3.protocol和继承区别

  • 继承之后默认就有实现, 而protocol只有声明没有实现
  • 相同类型的类可以使用继承, 但是不同类型的类只能使用protocol
  • protocol可以用于存储方法的声明, 可以将多个类中共同的方法抽取出来, 以后让这些类遵守协议即可

26.4.protocol 的使用注意

  • 1)Protocol:就一个用途,用来声明一大堆的方法(不能声明成员变量),不能写实现。
  1. @protocol SportProtocol <NSObject>
  2. {
  3. int _age; // 错误写法
  4. }
  5. – (void)playFootball;
  6. – (void)playBasketball;
  7. @end
  • 2)只要父类遵守了某个协议,那么子类也遵守。
  1. @protocol SportProtocol <NSObject>
  2. – (void)playFootball;
  3. – (void)playBasketball;
  4. @end
  1. #import “SportProtocol.h”
  2. @interface Student : NSObject <SportProtocol>
  3. @end
  4. @interface GoodStudent : Student
  5. @end
  6. @implementation GoodStudent
  7. – (void)playFootball
  8. {
  9. NSLog(@”%s”, __func__);
  10. }
  11. – (void)playBasketball
  12. {
  13. NSLog(@”%s”, __func__);
  14. }
  15. @end
  • 3)OC不能继承多个类(单继承)但是能够遵守多个协议。继承(:),遵守多个协议使用“< >”(尖括号)协议和协议直接用“,”(逗号)隔开。
  1. #import “SportProtocol.h”
  2. #import “StudyProtocol.h”
  3. @interface Student : NSObject <SportProtocol, StudyProtocol>
  4. @end
  • 4)协议可以遵守协议,一个协议遵守了另一个协议,就可以拥有另一份协议中的方法声明
  1. @protocol A
  2. -(void)methodA;
  3. @end
  4. @protocol B <A>
  5. -(void)methodB;
  6. @end
  1. @interface Student : NSObject <B>
  2. -(void)methodA; // 同时拥有A/B协议中的方法声明
  3. -(void)methodB;
  4. @end

26.5.基协议

  • NSObject是一个基类,*根本*基本的类,任何其他类*终都要继承它
  • 还有也叫NSObject的协议,它是一个基协议,*根本*基本的协议
  • NSObject协议中声明很多*基本的方法
    • description
    • retain
    • release
  • 建议每个新的协议都要遵守NSObject协议
  1. @protocol SportProtocol <NSObject> // 基协议
  2. – (void)playFootball;
  3. – (void)playBasketball;
  4. @end

26.6.@required和@optional关键字

  • 协议中有2个关键字可以控制方法是否要实现(默认是@required,在大多数情况下,用途在于程序员之间的交流)
    • @required:这个方法必须要实现(若不实现,编译器会发出警告)
    • @optional:可选的,这个方法不一定要实现。
  1. @protocol SportProtocol <NSObject>
  2. @required // 如果遵守协议的类不实现会报警告
  3. – (void)playFootball;
  4. @optional // 如果遵守协议的类不实现不会报警告
  5. – (void)playBasketball;
  6. @end

27.delegate-代理

27.1.代理设计模式

  • 生活中大家一定遇到这样的情况了:比如说我要买一包纸,不妨就是心相印的吧,那一般人的话我应该不是去心相印的工厂里面直接去买吧,而是我们在心相印专卖店或者什么超市啊,这些地方购买,这些地方实际上就是洁丽雅毛巾的代理。这其实和我们OO中的代理模式是很相似的。在OC中到处都在使用代理,可以说代理设计模式是OC中*重要*常用的设计模式之一。
  • 代理设计模式的场合:
    • 当对象A发生了一些行为,想告知对象B(让对象B成为对象A的代理对象)
    • 对象B想监听对象A的一些行为(让对象B成为对象A的代理对象)
    • 当对象A无法处理某些行为的时候,想让对象B帮忙处理(让对象B成为对象A的代理对象)

2.代理设计模式示例

  • 婴儿吃饭睡觉
  1. #import <Foundation/Foundation.h>
  2. @class Baby;
  3. // 协议
  4. @protocol BabyProtocol <NSObject>
  5. – (void)feedWithBaby:(Baby *)baby;
  6. – (void)hypnosisWithBaby:(Baby *)baby;
  7. @end

给baby定义了一个协议BabyProtocol,里面有两个方法,分别是吃饭和睡觉。该协议继承了基协议<NSObject>

  1. #import “BabyProtocol.h”
  2. @interface Baby : NSObject
  3. // 食量
  4. @property (nonatomic, assign) int food;
  5. // 睡意
  6. @property (nonatomic, assign) int drowsiness;
  7. // 饿
  8. – (void)hungry;
  9. // 睡意
  10. – (void)sleepy;
  11. @property (nonatomic, strong) id<BabyProtocol> nanny;
  12. @end
  13. @implementation Baby
  14. – (void)hungry
  15. {
  16. self.food -= 5;
  17. NSLog(@”婴儿饿了”);
  18. // 通知保姆,respondsToSelector:判断保姆类中是否实现了feedWithBaby:方法,如果没有实现该方法就不会执行。
  19. if ([self.nanny respondsToSelector:@selector(feedWithBaby:)]) {
  20. [self.nanny feedWithBaby:self];
  21. }
  22. }
  23. – (void)sleepy
  24. {
  25. self.drowsiness += 5;
  26. NSLog(@”婴儿困了”);
  27. // 通知保姆
  28. if ([self.nanny respondsToSelector:@selector(hypnosisWithBaby:)]) {
  29. [self.nanny hypnosisWithBaby:self];
  30. }
  31. }
  32. @end

baby类的匿名分类中定义了,食量,睡意两个int类型属性,定义了id类型的nanny属性,协议属性使用id类型的原因是代表任何类都可以遵守BabyProtocol协议,扩展性强。同时定义了两个hungry,sleepy(睡觉)两个方法。

  1. // 保姆
  2. @interface Nanny : NSObject <BabyProtocol>
  3. @end
  4. @implementation Nanny
  5. – (void)feedWithBaby:(Baby *)baby
  6. {
  7. baby.food += 10;
  8. NSLog(@”给婴儿喂奶, 现在的食量是%i”, baby.food);
  9. }
  10. – (void)hypnosisWithBaby:(Baby *)baby
  11. {
  12. baby.drowsiness += 10;
  13. NSLog(@”哄婴儿睡觉, 现在的睡意是%i”, baby.drowsiness);
  14. }
  15. @end

Nanny保姆类遵守了BabyProtocol协议,在baby发生饿了的行为时,会通知保姆,调用对应的方法。

  1. int main(int argc, const char * argv[]) {
  2. // 1.创建婴儿
  3. Baby *b = [Baby new];
  4. // 2.创建保姆
  5. Nanny *n = [Nanny new];
  6. // 3.保姆作为婴儿的代理
  7. b.nanny = n;
  8. // 4.换保姆
  9. // Studnet *stu = [Studnet new];
  10. //保姆属性id类型的,任何类都可以作为代理
  11. // b.nanny = stu;
  12. //5.婴儿发飙,执行food方法,food方法会执行保姆类的对应方法。
  13. [b food];
  14. [b sleepy];
  15. return 0;
  16. }

28.Foundation框架介绍

28.1.Foundation框架介绍

iOS提供了很多你可以在应用程序里调用的框架。要使用一个框架,需要将它添加到你的项目中,你的项目才可以使用它。许多应用程序都使用了如 Foundation、UIKit、和Core Graphics这些框架。根据你为应用程序选择的模版,相关的框架就已经被自动引入了。如果默认加入的框架不能满足你的应用程序的需求,你也可以加入需要的框架。
iOS应用程序基于Foundation和UIKit框架,在开发iOS程序时,主要使用框架就是Foundation和UIKit,因为它们包含了你需要的大部分东西。
每个框架对应IOS系统里的一层,每层建立在它下面层的上面。应该尽量使用上层的框架来代替下面的框架。更高层次的框架是对底层框架基于对象的抽象。
这两个框架在系统中的位置如下图:

%title插图%num
  1. + core os 核心操作系统
  2. + core services 核心服务层
  3. + core os 多媒体层
  4. + core os 核心触摸层(基础的UI类库,开发中经常使用到)
  5. + application 应用程序层
  • UIKit类层级结构
    %title插图%num
  • Foundation框架的作用
    • Foundation框架为所有的应用程序提供基本系统服务,也就是说Foundation框架是Mac\iOS中其他框架的基础
    • Foundation框架包含了很多开发中常用的数据类型:
      • 结构体
      • 枚举
  • 如何使用Foundation框架
    • Foundation框架中大约有125个可用的头文件,作为一个简单的形式,可以简单地使用以下语句导入#import<Foundation/Foundation.h>因为Foundation.h文件实际上导入其他所有Foundation框架中的头文件
  • Foundation框架中的类
    • Foundation框架允许使用一些基本对象,如数字和字符串,以及一些对象集合,如数组,字典和集合,其他功能包括处理日期和时间、内存管理、处理文件系统、存储(或归档)对象、处理几何数据结构(如点和长方形)
    • Foundation框架提供了非常多好用的类, 比如
      1. NSString : 字符串
      2. NSArray : 数组
      3. NSDictionary : 字典
      4. NSDate : 日期
      5. NSData : 数据
      6. NSNumber : 数字
  • Foundation框架中的类都是以NS为前缀(Next Step的缩写)
    • 乔布斯于1976年创立苹果公司
    • 乔布斯于1985年离开苹果公司, 创立NeXT公司, 开发了Next Step操作系统
    • 在开发Next Step操作系统过程中产生了Foundation框架
    • 1997年, 苹果公司收购NeXT公司, 乔布斯重返苹果公司(Mac系统就是基于Next Step系统)
    • 2007年, 苹果公司发布了iOS系统(iOS系统基于Mac系统)
  • Foundation框架常见错误
    • 有时候会在不经意之间修改了系统自带的头文件, 比如NSString.h, 这时会出现以下错误:
      %title插图%num
    • 解决方案, 只需要删除Xcode的缓存即可
      • 缓存路径是/Users/用户名/Library/Developer/Xcode/DerivedData(默认情况下, 这是一个隐藏文件夹)
    • 要想看到上述文件夹, 必须在终端敲指令显示隐藏文件夹, 指令如下
      • 显示隐藏文件 : defaults write com.apple.finder AppleShowAllFiles –bool true
      • 隐藏隐藏文件 : defaults write com.apple.finder AppleShowAllFiles –bool false
      • (输入指令后, 一定要重新启动Finder)

29.NSString和NSMutableString

  • NSString其实是一个对象类型。NSString是NSObject(Cocoa Foundation的基础对象)的子类,不可改变字符串,NSMutableString为可变的字符串。
    NSString 与 char *大的区别就是 NSString是一个objective对象,而char 是一个字节数组。@+” 字符串 ” 这个符号为objective-c NSString 字符串常量的标准用法,char* 创建的时候 无需添加@。每一个字符串其实是由若干个char字符组成,字符串的遍历实际上就是将字符串中的每一个字符提取出来。
    NSString 提供2个消息,length和characterAtIndex
    NSString 核心基础接口为CFStringRef

29.1.直接读写文件中的字符

  • 从文件中读取
  1. // 用来保存错误信息
  2. NSError *error = nil;
  3. // 读取文件内容
  4. NSString *str = [NSString stringWithContentsOfFile:@”/Users/XXX/Desktop/abc.txt” encoding:NSUTF8StringEncoding error:&error];
  5. // 如果有错误信息
  6. if (error) {
  7. NSLog(@”读取失败, 错误原因是:%@”, [error localizedDescription]);
  8. } else { // 如果没有错误信息
  9. NSLog(@”读取成功, 文件内容是:\n%@”, str);
  10. }
  • 写入文件中
  1. NSString *str = @”江哥”;
  2. BOOL flag = [str writeToFile:@”/Users/XXX/Desktop/abc.txt” atomically:YES encoding:NSUTF8StringEncoding error:nil];
  3. if (flag == 1)
  4. {
  5. NSLog(@”写入成功”);
  6. }
  • 重复写入同一文件会覆盖掉上一次的内容
  1. NSString *str1 = @”支付宝”;
  2. BOOL flag = [str1 writeToFile:@”/Users/XXX/Desktop/abc.txt” atomically:YES encoding:NSUTF8StringEncoding error:nil];
  3. NSString *str2 = @”暖宝宝”;
  4. [str2 writeToFile:@”/Users/XXX/Desktop/abc.txt” atomically:YES encoding:NSUTF8StringEncoding error:nil];
  5. NSString *str = [NSString stringWithContentsOfFile:@”/Users/XXX/Desktop/abc.txt” encoding:NSUTF8StringEncoding error:&error];
  6. NSLog(@”str = %@”, str);
  7. 输出结果:暖宝宝

29.2.NSString大小写处理

  • 全部字符转为大写字母
    • – (NSString *)uppercaseString;
  • 全部字符转为小写字母
    • – (NSString *)lowercaseString
  • 首字母变大写,其他字母都变小写
    • – (NSString *)capitalizedString

29.3.NSString比较

  • – (BOOL)isEqualToString:(NSString *)aString;
    • 两个字符串的内容相同就返回YES, 否则返回NO
  1. NSString *str1 = @”gzs”;
  2. NSString *str2 = [NSString stringWithFormat:@”gzs”];
  3. if ([str1 isEqualToString:str2]) {
  4. NSLog(@”字符串内容一样”);
  5. }
  6. if (str1 == str2) {
  7. NSLog(@”字符串地址一样”);
  8. }
  • – (NSComparisonResult)compare:(NSString *)string;
    • 这个方法可以用来比较两个字符串内容的大小
    • 比较方法: 逐个字符地进行比较ASCII值,返回NSComparisonResult作为比较结果
    • NSComparisonResult是一个枚举,有3个值:
      • 如果左侧 > 右侧,返回NSOrderedDescending,
      • 如果左侧 < 右侧,返回NSOrderedAscending,
      • 如果左侧 == 右侧返回NSOrderedSame
  1. NSString *str1 = @”abc”;
  2. NSString *str2 = @”abd”;
  3. switch ([str1 compare:str2]) {
  4. case NSOrderedAscending:
  5. NSLog(@”后面一个字符串大于前面一个”);
  6. break;
  7. case NSOrderedDescending:
  8. NSLog(@”后面一个字符串小于前面一个”);
  9. break;
  10. case NSOrderedSame:
  11. NSLog(@”两个字符串一样”);
  12. break;
  13. }
  14. 输出结果: 后面一个字符串大于前面一个
  • – (NSComparisonResult) caseInsensitiveCompare:(NSString *)string;
    • 忽略大小写进行比较,返回值与compare:一致
  1. NSString *str1 = @”abc”;
  2. NSString *str2 = @”ABC”;
  3. switch ([str1 caseInsensitiveCompare:str2]) {
  4. case NSOrderedAscending:
  5. NSLog(@”后面一个字符串大于前面一个”);
  6. break;
  7. case NSOrderedDescending:
  8. NSLog(@”后面一个字符串小于前面一个”);
  9. break;
  10. case NSOrderedSame:
  11. NSLog(@”两个字符串一样”);
  12. break;
  13. }
  14. 输出结果:两个字符串一样

29.4.字符串搜索

  • – (BOOL)hasPrefix:(NSString *)aString;
    • 是否以aString开头
  • – (BOOL)hasSuffix:(NSString *)aString;
    • 是否以aString结尾
  • – (NSRange)rangeOfString:(NSString *)aString;
    • 用来检查字符串内容中是否包含了aString
    • 如果包含, 就返回aString的范围
    • 如果不包含, NSRange的location为NSNotFound, length为0

29.5.NSRange基本概念

  • NSRange是Foundation框架中比较常用的结构体, 它的定义如下:
  1. typedef struct _NSRange {
  2. NSUInteger location;
  3. NSUInteger length;
  4. } NSRange;
  5. // NSUInteger的定义
  6. typedef unsigned int NSUInteger;
  • NSRange用来表示事物的一个范围,通常是字符串里的字符范围或者数组里的元素范围
  • NSRange有2个成员
    • NSUInteger location : 表示该范围的起始位置
    • NSUInteger length : 表示该范围内的长度
  • 比如@“I love GZS”中的@“ GZS”可以用location为7,length为3的范围来表示

29.6.NSRange的创建

  • 有3种方式创建一个NSRange变量
  • 方式1
  1. NSRange range;
  2. range.location = 7;
  3. range.length = 3;
  • 方式2
  1. NSRange range = {7, 3};
  2. 或者
  3. NSRange range = {.location = 7,.length = 3};
  • 方式3 : 使用NSMakeRange函数
NSRange range = NSMakeRange(7, 3);

29.7.字符串的截取

  • – (NSString *)substringFromIndex:(NSUInteger)from;
    • 从指定位置from开始(包括指定位置的字符)到尾部
      1. NSString *str = @”<head>暖宝宝</head>“;
      2. str = [str substringFromIndex:7];
      3. NSLog(@”str = %@”, str);
      4. 输出结果: 暖宝宝</head>
  • – (NSString *)substringToIndex:(NSUInteger)to;
    • 从字符串的开头一直截取到指定的位置to,但不包括该位置的字符
      1. NSString *str = @”<head>暖宝宝</head>”;
      2. str = [str substringToIndex:10];
      3. NSLog(@”str = %@”, str);
      4. 输出结果: <head>暖宝宝
  • – (NSString *)substringWithRange:(NSRange)range;
    • 按照所给出的NSRange从字符串中截取子串
      1. NSString *str = @”<head>暖宝宝</head>”;
      2. NSRange range;
      3. /*
      4. range.location = 6;
      5. range.length = 3;
      6. */
      7. range.location = [str rangeOfString:@”>”].location + 1;
      8. range.length = [str rangeOfString:@”</”].location – range.location;
      9. NSString *res = [str substringWithRange:range];
      10. NSLog(@”res = %@”, res);
      11. 输出结果: 暖宝宝

29.8.字符串的替换函数

  • – (NSString )stringByReplacingOccurrencesOfString:(NSString )target withString:(NSString *)replacement;
    • 用replacement替换target
  1. NSString *str = @”http:**baidu.com*img*ljn.gif”;
  2. NSString *newStr = [str stringByReplacingOccurrencesOfString:@”*” withString:@”/”];
  3. NSLog(@”newStr = %@”, newStr);
  4. 输出结果: http://www.baidu.com/img/ljn.gif
  • – (NSString )stringByTrimmingCharactersInSet:(NSCharacterSet )set;
    • 去除首尾
  1. NSString *str = @” http://baidu.com/img/ljn.gif “;
  2. NSString *newStr = [str stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
  3. NSLog(@”str =|%@|”, str);
  4. NSLog(@”newStr =|%@|”, newStr);
  5. 输出结果:
  6. str =| http://baidu.com/img/ljn.gif |
  7. newStr =|http://baidu.com/img/ljn.gif|
  1. NSString *str = @”***http://baidu.com/img/ljn.gif***”;
  2. NSString *newStr = [str stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@”*”]];
  3. NSLog(@”str =|%@|”, str);
  4. NSLog(@”newStr =|%@|”, newStr);
  5. 输出结果:
  6. str =|***http://baidu.com/img/ljn.gif***|
  7. newStr =|http://baidu.com/img/ljn.gif|

29.9.NSString与路径

  • – (BOOL)isAbsolutePath;
    • 是否为*对路径
      1. // 其实就是判断是否以/开头
      2. // NSString *str = @”/Users/My-Lee/Desktop/bai.txt”;
      3. NSString *str = @”Users/My-Lee/Desktop/bai.txt”;
      4. if ([str isAbsolutePath]) {
      5. NSLog(@”是*对路径”);
      6. }else
      7. {
      8. NSLog(@”不是*对路径”);
      9. }
  • – (NSString *)lastPathComponent;
    • 获得*后一个目录
      1. // 截取*后一个/后面的内容
      2. NSString *str = @”/Users/My-Lee/Desktop/bai.txt”;
      3. NSString *component = [str lastPathComponent];
      4. NSLog(@”component = %@”, component);
  • – (NSString *)stringByDeletingLastPathComponent;
    • 删除*后一个目录
      1. // 其实就是上次*后一个/和之后的内容
      2. NSString *str = @”/Users/My-Lee/Desktop/bai.txt”;
      3. NSString *newStr = [str stringByDeletingLastPathComponent];
      4. NSLog(@”newStr = %@”, newStr);
  • – (NSString )stringByAppendingPathComponent:(NSString )str;
    • 在路径的后面拼接一个目录
      (也可以使用stringByAppendingString:或者stringByAppendingFormat:拼接字符串内容)

      1. // 其实就是在*后面加上/和要拼接得内容
      2. // 注意会判断后面有没有/有就不添加了, 没有就添加, 并且如果有多个会替换为1个
      3. // NSString *str = @”/Users/My-Lee/Desktop”;
      4. NSString *str = @”/Users/My-Lee/Desktop/”;
      5. NSString *newStr = [str stringByAppendingPathComponent:@”bai”];
      6. NSLog(@”newStr = %@”, newStr);

29.10.NSString与文件拓展名

  • – (NSString *)pathExtension;
    • 获得拓展名
      1. // 其实就是从*后面开始截取.之后的内容
      2. // NSString *str = @”abc.txt”;
      3. NSString *str = @”abc.txt”;
      4. NSString *extension = [str pathExtension];
      5. NSLog(@”extension = %@”, extension);
  • – (NSString *)stringByDeletingPathExtension;
    • 删除尾部的拓展名
      1. // 其实就是上次从*后面开始.之后的内容
      2. // NSString *str = @”abc.txt”;
      3. NSString *str = @”abc.txt”;
      4. NSString *newStr = [str stringByDeletingPathExtension];
      5. NSLog(@”newStr = %@”, newStr);
  • – (NSString )stringByAppendingPathExtension:(NSString )str;
    • 在尾部添加一个拓展名
      1. // 其实就是在*后面拼接上.和指定的内容
      2. NSString *str = @”abc”;
      3. NSString *newStr = [str stringByAppendingPathExtension:@”gif”];
      4. NSLog(@”newStr = %@”, newStr);

29.11.字符串和其他数据类型转换

  • 转为基本数据类型
    • – (double)doubleValue;
    • – (float)floatValue;
    • – (int)intValue;
      1. NSString *str1 = @”110″;
      2. NSString *str2 = @”10″;
      3. int res = str1.intValue + str2.intValue;
      4. NSLog(@”res = %i”, res);
      1. NSString *str1 = @”110″;
      2. NSString *str2 = @”10.1″;
      3. double res = str1.doubleValue + str2.doubleValue;
      4. NSLog(@”res = %f”, res);
  • 转为C语言中的字符串
    • – (char *)UTF8String;
      1. NSString *str = @”abc”;
      2. const char *cStr = [str UTF8String];
      3. NSLog(@”cStr = %s”, cStr);
      1. char *cStr = “abc”;
      2. NSString *str = [NSString stringWithUTF8String:cStr];
      3. NSLog(@”str = %@”, str);

29.12.NSMutableString 基本概念

  • NSMutableString 类 继承NSString类,那么NSString

云计算有SPI,即SaaS、PaaS和IaaS三种服务模式,三者之间的关系,谁能讲的清楚

云计算有SPI,即SaaS、PaaS和IaaS三种服务模式,这是目前被业界*广泛认同的划分。虽然它们已业内多数人所熟知,但是对于三者之间的关系,能够道清的为数不多。下文将帮助大家近一步明晰:

“层次”的不同

这里所谓的“层次”,是分层体系架构意义上的“层次”。首先,基础设施即服务(IaaS)在基础设施层实现,Iaas通过网络向用户提供计算机(物理机和虚拟机)、存储空间、网络连接、负载均衡和防火墙等基本计算资源;用户在此基础上部署和运行各种软件,包括操作系统和应用程序。其次,平台即服务(PaaS)是在软件开放运行平台层实现,PaaS实际上是指将软件研发的平台作为一种服务,以SaaS的模式提交给用户,PaaS是SaaS模式的一种。

*后,软件即服务(SaaS)由应用软件层实现,它是一种通过Internet提供软件的模式,用户无需购买软件,而是向提供商租用基于Web的软件,来管理企业经营活动。

进入PaaS之前,须有IaaS

正如前面说到的,它们存在着“层次”的不同,在实施PaaS之前,须有IaaS提供的服务基础。*步是迈向资源共享,也就是常见的虚拟化,如果没有在此基础上持续改进的话,那么拥有一个高度虚拟化的环境的价值值得怀疑;第二步是业界需要持续不断地在实践中推动和简化资源池的使用和管理,这将使得客户从虚拟化演进的*步中也受益匪浅,而且能够有效地满足客户的需求。从IaaS迁移到PaaS相对富有挑战性,*困难的挑战之一是选择方法和架构,在有些时候,平台可以简单到只是一系列的虚拟机的组合。

三者的界限开始模糊

基于云的基础设施即服务(IaaS)是指从服务供应商租用存储和计算能力,通过互联网连接提供给用户。同样,软件即服务(SaaS)是用于访问托管在云中的应用程序。平台即服务(PaaS)有点像是介于这两者之间,提供在云中的应用程序开发和托管平台。在很多方面,PaaS结合了基础设施即服务和软件及服务的元素。

*近,有研究人员在密切追踪PaaS之后表示,IaaS、PaaS和SaaS三者之间的界限开始模糊,例如亚马逊正在为自己的IaaS服务添加类似PaaS的功能。驱动它们界限变得模糊的因素有两个,其一是供应商正在试图扩大其服务产品范围来吸引更广泛的客户群;其二是用户正在以新方式使用云计算,他们期待从其供应商获取想要的功能。

随着云计算技术的成熟,云计算解决方案必然向着集成化的方向转变,这不仅是市场消费群体的需求,更是云计算编码人员、快速开发人员工作的需要。三种模式融合化的趋势,有利于云计算市场的快速健康发展。

 

ios 基本语法介绍(上篇)

因为*近在学ios了,其实本来老早就开始学了,但一直没啥大的突破,知道*近我们的c++课上到多态哪里之后,再来看oc,突然就通了····不知道怎么回事····

下面是我在简书上看到的oc的基础语法。

objectve-C语法总结<1>

大纲


  • 0.OC数据类型
  • 1.声明一个类
  • 2.实现一个类
  • 3.创建一个对象
  • 4.对象的注意点
  • 5.对象方法
  • 6.类方法
  • 7.getter/setter方法
  • 8.点语法
  • 9.self关键字
  • 10.OC中的继承
  • 11.super关键字
  • 12.OC中的多态
  • 13.实例变量访问修饰符
  • 14.私有变量和私有方法
  • 15.@property概念
  • 16.@property修饰符
  • 17.id类型
  • 18.new方法实现原理
  • 19.构造方法
  • 20.instancetype与id
  • 21.类的启动过程
  • 22.SEL介绍
  • 23.@class使用
  • 24.注释和指令
  • 25.分类
  • 26.Block

0.OC中的数据类型

  • OC是增强了C的特性,所以在变量和基本数据类型上基本与C一致。
  • 在OC中变量命名有如下规则:
    • 由字母、数字、下划线、$符号组成
    • 必须以字母、下划线、$符号开头
    • 大小写敏感
  • OC中有如下基本数据类型:
关键字 数据类型
int: 声明整型变量
double: 声明双精度变量
float: 声明浮点型变量
char: 声明字符型变量
id: 通用的指针类型
enum: 声明枚举类型
long: 声明长整型变量或函数
short: 声明短整型变量或函数
signed: 声明有符号类型变量
struct: 声明结构体变量
union: 声明共用体(联合)数据类型
unsigned: 声明无符号类型变量
void: 声明函数无返回值或无参
  • 数据类型格式化字符:
数据类型 oc关键字 格式说明引导符
整型 int %d.%i
短整型 short int %hd.%hi
长整型 long int %ld.%li
无符号短整型 unsigned int %u
无短整型 unsigned short %hu
无符号长整型 unsigned long %lu
浮点型 float %f
双精度型 double %f
长双精度型 long double %lf
字符型 char %c
  • 举例
  1. #import <Foundation/Foundation.h>
  2. int main(int argc, const char * argv[])
  3. {
  4. @autoreleasepool {
  5. //保留字是不能定义为变量名的,例如下面的int、float等就不能作为变量名
  6. int i = 2;
  7. float f = 2.3f;
  8. double d = 2.3e12;
  9. char c = ‘a’;
  10. //输出数据
  11. NSLog(@”i : %d”,i);
  12. NSLog(@”f : %f 截取后 : %.2f”,f,f);
  13. NSLog(@”d : %e 截取后 : %.2e”,d,d);
  14. NSLog(@”c : %c , %d”,c ,c );
  15. //数据转换
  16. //数据类型容量大的转成小的可能会丢失精度
  17. int i2 = (int)f;
  18. float f2 = (float)i ;
  19. NSLog(@”数据转换”);
  20. NSLog(@”i2 : %d”,i2);
  21. NSLog(@”f2 : %f”,f2);
  22. NSLog(@”变量的作用域”);
  23. if(YES){
  24. int i3 = 2;
  25. NSLog(@”i3 : %d”,i3);
  26. }
  27. //在if的{}外面是无法访问到内部的i3变量的,因为i3变量的作用域就只是那对{}内部
  28. //NSLog(@”i3 : %d”,i3);
  29. /*
  30. 运行结果
  31. [859:303] i : 2
  32. [859:303] f : 2.300000 截取后 : 2.30
  33. [859:303] d : 2.300000e+12 截取后 : 2.30e+12
  34. [859:303] c : a , 97
  35. [859:303] 数据转换
  36. [859:303] i2 : 2
  37. [859:303] f2 : 2.000000
  38. */
  39. }
  40. return 0;
  41. }

1.声明一个类

  • 格式
    %title插图%num
  • 注意:
    • 1.必须以@interface开头,@end结尾
    • 2.成员变量的声明,必须写在@interface与@end之间的大括号中
    • 3.方法的声明必须在{}下面,不能写在{}中

2.实现一个类

  • 格式
  1. @implementation MyClass
  2. // 对象方法
  3. – (id)initWithString:(NSString *)aName
  4. {
  5. //TODO
  6. }
  7. // 类方法
  8. + (MyClass *)myClassWithString:(NSString *)aName
  9. {
  10. //TODO
  11. }
  12. @end
  • 注意:
    • 1.必须以@implementation开头,@end结尾
    • 2.类名必须和声明的一致

3.创建一个对象

  • 用类的方式告诉计算机,我们需要一个什么样的对象,之后我们要在程序中使用这个对象,就必须先创建一个对象
%title插图%num
  • 注意[Car new];做了三件事
    • 1.在堆内存中开辟了一块新的存储空间
    • 2.初始化成员变量(写在类声明大括号中的属性就叫成员变量,也叫实例变量)
    • 3.返回指针地址
  • 消息机制
    • 使用对象调用方法就是OC中的消息机制
    • OC中调用方法的格式:[类名或者对象名 方法名];
      %title插图%num

4.对象的注意点

  • 可以通过 对象->对象成员(注意声明属性为:@public) 的方式访问对象中的成员,
  • 每一个对象中都有一份属于自己的属性。
  • 对其中一个对象的成员进行了修改。和另一个对象没有关系

5.对象方法

5.1.对象方法的声明

  • 格式
    %title插图%num
  • 特征
    • 对象方法以-开头如 -(void)xx;
    • 对象方法只能由对象来调用
    • 对象方法中可以访问当前对象的成员变量
    • 调用格式 [对象名 对象方法名];
  • 示例
    • 在MyClass.h文件中声明
  1. @interface MyClass : NSObject
  2. //声明没有返回值的方法
  3. – (void)method;
  4. //声明有返回值的方法
  5. – (int)newMethod;
  6. //声明有返回值有参数的方法
  7. – (int)method: (int)var;
  8. //声明有返回值有多个参数的方法
  9. – (int)method: (int)var1 andVar2: (int)var2;
  10. @end

5.2.对象方法实现

  • 在MyClass.m文件中实现
  1. @implementation MyClass
  2. //声明没有返回值的方法
  3. – (void)method{
  4. // TODO
  5. }
  6. //声明有返回值的方法
  7. – (int)newMethod{
  8. // TODO
  9. return 10;
  10. }
  11. //声明有返回值有参数的方法
  12. – (int)method: (int)var{
  13. // TODO
  14. return 20;
  15. }
  16. //声明有返回值有多个参数的方法
  17. – (int)method: (int)var1 andVar2: (int)var2{
  18. // TODO
  19. return 30;
  20. }
  21. @end
  • 必须以@implementation开头,@end之间
  • 在声明的后面加上{}即表示实现
  • 需要实现的代码写在{}中

6.类方法

6.1.类方法声明

  • 格式
    • 将对象方法-号变为+号
  • 特征(很像java中静态方法)
    • 类方法以+开头 如+(void)put;
    • 类方法只能由类来调用
    • 类方法中不能访问实例(成员)变量,因为类方法由类来调用,并没有创建存储空间 来存储类中的成员变量。
  • 类方法的好处:
    • 节省内存空间
    • 不依赖于对象,执行效率更高;
    • 能用类方法解决的问题,尽量使用类方法;
  • 类方法的场合:
    • 当方法内部不需要使用到成员变量时,可以改为类方法
    • 类方法一般用于编写工具方法
  • 示例
  1. //声明没有返回值的方法
  2. + (void)method;
  3. //声明有返回值的方法
  4. + (int) newMethod;
  5. //声明有返回值有参数的方法
  6. + (int)method: (int)var;
  7. //声明有返回值有多个参数的方法
  8. + (int)method: (int)var1 andVar2: (int)var2;

6.2.类方法实现

  1. //声明没有返回值的方法
  2. + (void)method{
  3. // TODO
  4. }
  5. //声明有返回值的方法
  6. + (int)newMethod{
  7. // TODO
  8. return 10;
  9. }
  10. //声明有返回值有参数的方法
  11. + (int)method: (int)var{
  12. // TODO
  13. return 20;
  14. }
  15. //声明有返回值有多个参数的方法
  16. + (int)method: (int)var1 andVar2: (int)var2{
  17. // TODO
  18. return 30;
  19. }
  • 必须卸载以@implementation开头,@end之间
  • 在声明的后面加上{}即表示实现
  • 将需要实现的代码写在{}中

6.3.对象方法和类方法区别

  • 对象方法
    • 对象方法是属于对象的
    • 以减号-开头
    • 只能让对象调用,没有对象,这个方法根本不可能被执行
    • 对象方法能访问实例变量(成员变量)
    • 对象方法中可以调用当前对象的对象方法
    • 对象方法中可以调用其他对象的对象方法
    • 对象方法中不可以调用类方法
  • 类方法
    • 类方法是属于类的
    • 以加号+开头
    • 只能用类名调用,对象不能调用
    • 类方法中不能直接访问实例变量(成员变量)
    • 类方法中不能直接调用对象方法,要想调用对象方法,必须创建或传入对象。
  • 使用场合:
    • 当不需要访问成员变量的时候,尽量用类方法
  • 类方法和对象方法可以同名

7.getter/setter方法

  • 代码实现和java基本一样
  1. @interface MyClass()
  2. {
  3. // 定义一个NSString(字符串)类型的属性Name
  4. NSString *Name;
  5. }
  6. @end
  7. @implementation MyClass
  8. // setter方法
  9. – (void)setName:(NSString *)name{
  10. Name = name;
  11. }
  12. // getter方法
  13. – (NSString *)name{
  14. return name;
  15. }
  16. @end

8.点语法

8.1点语法的本质

  • 其实点语法的本质还是方法调用
  • 当使用点语法时,编译器会自动展开成相应的方法
%title插图%num
  • 当点语法使用在 “=“赋值符号左侧的时候,点语法会被展开为setter方法的调用,其他情况(等号右侧、直接使用)为点语法展开为getter方法的调用

8.2点语法注意点

  • 点语法的本质是方法的调用,而不是访问成员变量,当使用点语法时,编译器会自动展开成相应的方法调用。
  • 点语法的本质是转换成相应的对setter和getter方法调用,如果没有set和get方法,则不能使用点语法。
  • 不在要再getter 与 setter方法中使用本属性的点语法
  1. – (void) setAge:(int)age {
  2. // 下面的代码会引发死循环
  3. self.age = age;
  4. //编译器展开后 [self setAge:age]
  5. }
  6. – (int) age {
  7. // 下面的代码会引发死循环
  8. return self.age;
  9. // 编译器展开后 [self age]
  10. }

9.self关键字

  • oc语言中的self,相当于java中的this关键字。
  • 在类方法中的self,代表的是类对象,可以通过self调用该类对象的其他类方法。
  • 在对象方法中self,代表的是该类的对象,可以通过self 关键字调用该对象的其他对象方法,同时也可以访问成员变量。

总结

  • 谁调用self所在的方法,那么self就是谁
  • self在类方法中就是这个类的类对象,全局只有一个,可通过self本类中的其他类方法,但是不能通过self来调用对象方法或访问成员变量
  • self在对象方法中,就是调用这个方法的那个对象, 可以通过self调用其他本类中其他的对象方法,访问成员变量,但不能通过self调用本类的类方法。
    • 通过self调用方法的格式:[self 方法名];
    • 通过self访问成员变量格式:self->成员变量名

10.OC中的继承

10.1继承语法

  • 在声明子类的时候,在子类名称后面通过:父类名称方式来实现继承。
    和java一样,OC也不能多继承。
  1. @interface 子类名称 : 父类名称
  2. @end

10.2方法重写

  • 在子类中实现与父类中同名的方法,称之为方法重写;
  • 重写以后当给子类发送这个消息的时候,执行的时在子类中重写的那个方法,而不是父类中的方法。
  • 如果在想在子类中调用被子类重写的父类的方法,可以通过super关键字
  • 使用场景:当从父类继承的某个方法不适合子类,可以在子类中重写父类的这个方法。
  1. – (void)viewDidLoad {
  2. // 调用父类的viewDidLoad方法。
  3. [super viewDidLoad];
  4. // 在重写方法中做一些操作
  5. NSLog(@”%@”,@”my first iOS project”);
  6. }

11.super关键字

  • 直接调用父类中的某个方法
  • super在对象方法中,那么就会调用父类的对象方法
    super在类方法中,那么就会调用父类的类方法

12.OC中的多态

  • Animal是父类,子类有Cat 和 Dog,子类分别重写了父类中的eat方法;实例化对象的时候可以用下面的方法:
  1. Animal *animal = nil;
  2. //实例化猫的对象
  3. animal = [Cat new];
  4. [animal eat];
  5. //实例化狗的对象
  6. animal = [Dog new];
  7. [animal eat];

13.实例变量访问修饰符

13.1.实例变量的作用域

%title插图%num

@public

  • 可以在其它类中访问被public修饰的成员变量
  • 也可以在本类中访问被public修饰的成员变量
  • 可以在子类中访问父类中被public修饰的成员变量

    @private

  • 不可以在其它类中访问被private修饰的成员变量
  • 可以在本类中访问被private修饰的成员变量
  • 不可以在子类中访问父类中被private修饰的成员变量

    @protected

  • 不可以在其它类中访问被protected修饰的成员变量
  • 可以在本类中访问被protected修饰的成员变量
  • 可以在子类中访问父类中被protected修饰的成员变量

    注意: 默认情况下所有的实例变量都是protected

    @package

  • 介于public和private之间的
  • 如果是在其它包中访问那么就是private的
  • 如果是在当前代码所在的包种访问就是public的
  1. @interface Person : NSObject
  2. {
  3. @public
  4. int _age;
  5. @private
  6. double _height;
  7. @protected// 默认就是protected
  8. double _weight;
  9. @package// 相当于public
  10. NSString *_name;
  11. NSString *_tel;
  12. NSString *_email;
  13. }
  14. @end

14.私有变量和私有方法

  • 在类的实现即.m文件中也可以声明成员变量,但是因为在其他文件中通常都只是包含头文件而不会包含实现文件,所以在.m文件中声明的成员变量是@private的。在.m中定义的成员变量不能和它的头文件.h中的成员变量同名。
  1. @interface MyClass()
  2. {
  3. NSString *Name;
  4. }
  5. @end
  6. @implementation MyClass
  7. //在.h文件中没有声明,只在.m文件中实现就是私有方法
  8. – (void)method{
  9. // TODO
  10. }
  11. @end

15.@property概念

  • @property是一个编译器指令。我*喜欢的一个功能之一。在java中类的每一个属性都有对应getter/setter方法。Eclipse等之类的IDE开发工具也集成了自动生成属性的getter/setter方法功能,但是还是需要程序员自己选中需要生成代码的属性然后生成。在oc中你只需要像这样一句话。So easy!
    1. @interface Person : NSObject
    2. @property int age;
    3. @end
  • 在使用@property定义属性之后,编译器都帮我们干了什么?
    • Xcode4.4之前
      编译器只要看到@property, 就知道我们要生产某一个属性的getter/setter方法的声明,相当于实现了如下的两个方法声明。

      1. – (void)setAge:(int)age;
      2. – (int)age;
    • Xcode4.4之后有爱的Apple对@property进行了一个增强。
      1.利用@property可以同时自动生成setter/getter方法的声明和实现。
      2.利用@property来生成getter/setter方法, 那么我们可以不写成员变量, 系统会自动给我们生成一个_开头的成员变量(@property自动帮我们生成的成员变量是一个私有的成员变量, 也就是说是在.m文件中生成的, 而不是在.h文件中生成的)

      1. //Person.h文件
      2. @interface Person : NSObject
      3. @property int age;
      4. /*
      5. // 相当于生成了如下的getter/setter方法的声明
      6. – (void)setAge:(int)age;
      7. – (int)age
      8. */
      9. @end
      10. //Person.m文件
      11. #import “Person.h”
      12. @@implementation Person
      13. @property int age;
      14. /*
      15. // 相当于生成了如下的getter/setter方法的实现
      16. – (void)setAge:(int)age
      17. {
      18. //_age编译器自动帮我们生成的私有成员变量
      19. _age = age;
      20. }
      21. – (int)age
      22. {
      23. return _age;
      24. }
      25. */
      26. @end

      3.@property只会生成*简单的getter/setter方法,而不会进行数据判断。如果想对传入的数据进行过滤, 那么我们就必须重写getter/setter方法。如果不想对传入的数据进行过滤, 仅仅是提供一个方法给外界操作成员变量, 那么就可以使用@property。

      • 如果重写了setter方法, 那么@property就只会生成getter方法
        1. - (void)setAge:(int)age
        2. {
        3. //对传递过来的age进行过滤
        4. if (age < 0) {
        5. age = 0;
        6. }
        7. _age = age;
        8. }
      • 如果重写了getter方法, 那么@property就只会生成setter方法
        1. – (int)age
        2. {
        3. return _age;
        4. }
        • 如果同时重写了getter/setter方法, 那么@property就不会自动帮我们生成私有的成员变量。
          %title插图%num

16. @property修饰符

  • 修饰是否生成getter方法的
    • readonly 只生成setter方法,不生成getter方法
    • readwrite 既生成getter 又生成setter方法(默认)
      @property (readonly) int age;
  • 指定所生成的方法的方法名称
    • getter=你定制的getter方法名称
    • setter=你定义的setter方法名称(注意setter方法必须要有 🙂
      1. @property (getter=isMarried) BOOL married;
      2. 说明,通常BOOL类型的属性的getter方法要以is开头
  • 多线程管理
    • atomic  :性能低(默认) 
    • nonatomic  :性能高(iOS开发中都用这个属性)
      @property (nonatomic)  NSString  *name;
  • 控制set方法的内存管理
    MRC(手动引用计数)

    • retain  :  release旧值,retain新值(用于OC对象) 
    • assign  :  直接赋值,不做任何内存管理(默认,用于非OC对象类型) 
    • copy  :  release旧值,copy新值(一般用于NSString  *)

      ARC(自动引用计数)

    • strong  :  强引用,相当于MRC下的retain。用于OC对象。
    • weak  :  弱引用,相当于MRC下的assign。一般用来防止循环引用。
    • copy  :  release旧值,copy新值(一般用于NSString  *)
      1. // MRC
      2. @property (nonatomic, retain) User *user;
      3. @property (nonatomic, assign) int age;
      4. @property (nonatomic, copy) NSString *name;
      5. // ARC
      6. @property (nonatomic, strong) User *user;
      7. @property (nonatomic, assign) int age;
      8. @property (nonatomic, weak) UIView *view;
      9. @property (nonatomic, copy) NSString *name;
      10. 说明,此处大概了解下内存管理,后面会详细的说明。
  • 总结
    %title插图%num

17.id类型

17.1.静态类型和动态类型

  • 静态类型
    • 在编译的时候就知道这个指针变量所属的类,这个这个变量总是存储特定类的对象。
      Person *p = [Person new];
  • 动态类型
    • 这一特性是程序直到执行时才确定对象所属的类
      id obj = [Person new];

17.2.为什么要有动态类型?

  • 我们知道NSObject是OC中的基类(相当于java中object)
  • 那么任何对象的NSObject类型的指针可以指向任意对象,都没有问题
  • 但是NSObject是静态类型,如果通过它直接调用NSObject上面不存在的方法,编译器会报错。
  • 你如果想通过NSObject的指针调用特定对象的上面,就必须把NSObject * 这种类型强转成特定类型。然后调用。如下
  1. //定义NSObject * 类型
  2. NSObject* obj = [Cat new];
  3. //需要强制类型转换
  4. Cat *c = (Cat*)obj
  5. [c eat];
  • id 是一种通用的对象类型,它可以指向属于任何类的对象,也可以理解为万能指针 ,相当于C语言的 void *
  • 因为id是动态类型,所以可以通过id类型直接调用指向对象中的方法, 编译器不会报错
  1. /// Represents an instance of a class.
  2. struct objc_object {
  3. Class isa OBJC_ISA_AVAILABILITY;
  4. };
  5. /// A pointer to an instance of a class.
  6. typedef struct objc_object *id;
  1. id obj = [C at new];
  2. [obj eat]; // 不用强制类型转换
  3. [obj test]; //可以调用私有方法
  • 注意:
    • 在id的定义中,已经包好了*号。Id指针只能指向OC中的对象
    • 为了尽可能的减少编程中出错,Xcode做了一个检查,当使用id 类型的调用本项目中所有类上都没有的方法,编译器会报错
    • id类型不能使用.语法, 因为.语法是编译时特性, 而id是运行时特性

17.3.id数据类型与静态类型

  • 虽然说id数据类型可以存储任何类型的对象,但是不要养成滥用这种通用类型
    • 如没有使用到多态尽量使用静态类型
    • 静态类型可以更早的发现错误(在编译阶段而不是运行阶段)
    • 静态类型能够提高程序的可读性
    • 使用动态类型前*好其真实类型
  • 动态类型判断类型
    • – (BOOL)isKindOfClass:classObj 判断实例对象是否是这个类或者这个类的子类的实例
  1. Person *p = [Person new];
  2. Student *stu = [Student new];
  3. BOOL res = [p isKindOfClass:[Person class]];
  4. NSLog(@“res = %i”, res); // YES
  5. res = [stu isKindOfClass:[Person class]];
  6. NSLog(@“res = %i”, res); // YES
  • – (BOOL) isMemberOfClass: classObj 判断是否是这个类的实例
  1. Person *p = [Person new];
  2. Student *stu = [Student new];
  3. BOOL res = [p isMemberOfClass:[Person class]];
  4. NSLog(@“res = %i”, res); // YES
  5. res = [stu isMemberOfClass:[Person class]];
  6. NSLog(@“res = %i”, res); // NO
  • + (BOOL) isSubclassOfClass:classObj 判断类是否是指定类的子类)
  1. BOOL res = [Person isSubclassOfClass:[Student class]];
  2. NSLog(@“res = %i”, res); // NO
  3. res = [Student isSubclassOfClass:[Person class]];
  4. NSLog(@“res = %i”, res); // YES

18.new方法实现原理

  • java中创建一个对象:Person person = new Person();
    在OC中创建一个可用的对象:Person *p=[Person new];
    new方法的内部会分别调用两个方法来完成3件事情:

    • (1)使用alloc方法来分配存储空间(返回分配的对象);
    • (2)使用init方法来对对象进行初始化。
    • (3)返回对象的首地址
This method is a combination of alloc and init. Like alloc, it initializes the isa instance variable of the new object so it points to the class data structure. It then invokes the init method to complete the initialization process.
  • 可以把new方法拆开如下:
    • (1).调用类方法+alloc分配存储空间,返回未经初始化的对象Person *p1=[person alloc];
    • (2).调用对象方法-init进行初始化,返回对象本身
      Person *p2=[p1 init];
    • (3).以上两个过程整合为一句:Person *p=[[Person alloc] init];
  • 说明:
    • alloc 与 init合起来称为构造方法,表示构造一个对象
    • alloc 方法为对象分配存储空间,并将所分配这一块区域全部清0.
      The isa instance variable of the new instance is initialized to a data structure that describes the class; memory for all other instance variables is set to 0.
    • init方法是初始化方法(构造方法),用来对象成员变量进行初始化,默认实现是一个空方法。
      An object isn’t ready to be used until it has been initialized. The init method defined in the NSObject class does no initialization; it simply returns self.
  • 所以下面两句的作用是等价的
    1. Person *p1 = [Person new];
    2. Person *p = [[Person alloc] init];// 一般使用该方式创建对象
  • iOS 程序通常使用[[类名 alloc] init] 的方式创建对象,因为这个可以与其他initWithXX:…的初始化方法统一起来,代码风格保持一致。

19.构造方法

19.1.默认构造方法

  • OC的构造方法是以init开头,会java的同学要哭死了,然并卵。
  1. – (id)init {
  2. self = [super init];
  3. if (self) {
  4. // Initialize self.
  5. }
  6. return self;
  7. }
  8. //或者也可以这样
  9. //- (id)init {
  10. – (instancetype)init {
  11. if (self = [super init]) {
  12. // Initialize self.
  13. }
  14. return self;
  15. }
  • [super init]的作用:
    先利用父类的init方法为子类实例的父类部分属性初始化。稍微会点java的都知道什么意思,就不过多解释了。
  • self 为什么要赋值为[super init]:
    简单来说是为了防止父类的初始化方法release掉了self指向的空间并重新alloc了一块空间。还有[super init]可能alloc失败,这时就不再执行if中的语句。

19.2自定义构造方法

  • 自定义构造方法的规范
    • (1)一定是对象方法,以减号开头
    • (2)返回值一般是instancetype类型
    • (3)方法名必须以initWith开头
  • 自定义构造方法的声明
  1. @interface Person : NSObject
  2. @property int age;
  3. @property NSString *name;
  4. // 当想让对象一创建就拥有一些指定的值,就可以使用自定义构造方法
  5. – (instancetype)initWithAge:(int)age;
  6. – (instancetype)initWithName:(NSString *)name;
  7. – (instancetype)initWithAge:(int)age andName:(NSString *)name;
  8. @end
  • 自定义构造方法的实现
  1. #import “Person.h”
  2. @implementation Person
  3. – (instancetype)init
  4. {
  5. if (self = [super init]) {
  6. _age = 10;
  7. }
  8. return self;
  9. }
  10. – (NSString *)description
  11. {
  12. return [NSString stringWithFormat:@”age = %i, name = %@”, _age, _name];
  13. }
  14. – (instancetype)initWithAge:(int)age
  15. {
  16. if (self = [super init]) {
  17. _age = age;
  18. }
  19. return self;
  20. }
  21. – (instancetype)initWithName:(NSString *)name
  22. {
  23. if (self =[super init]) {
  24. _name = name;
  25. }
  26. return self;
  27. }
  28. – (instancetype)initWithAge:(int)age andName:(NSString *)name
  29. {
  30. if (self = [super init]) {
  31. _age = age;
  32. _name = name;
  33. }
  34. return self;
  35. }

19.3.自定义类工厂方法

  • 类工厂方法
    • 用于快速创建对象的类方法, 我们称之为类工厂方法
    • 类工厂方法中主要用于 给对象分配存储空间和初始化这块存储空间
  • 规范:
    • 一定是类方法 +
    • 方法名称以类的名称开头, 首字母小写
    • 一定有返回值, 返回值是id/instancetype
  • 自定义类工厂方法声明
  1. #import <Foundation/Foundation.h>
  2. @interface Person : NSObject
  3. @property int age;
  4. + (instancetype)person;
  5. + (instancetype)personWithAge:(int)age;
  6. @end
  • 自定义类工厂方法实现
  1. #import “Person.h”
  2. @implementation Person
  3. + (instancetype)person
  4. {
  5. return [[Person alloc] init];
  6. }
  7. + (instancetype)personWithAge:(int)age
  8. {
  9. Person *p = [[Person alloc] init];
  10. p.age = age;
  11. return p;
  12. }
  13. @end

20. instancetype与id

  • instancetype == id == 万能指针 == 指向一个对象。
  • id在编译的时候不能判断对象的真实类型
  • instancetype在编译的时候可以判断对象的真实类型
  • instancetype与id相似,不过instancetype只能作为方法返回值,它会进行类型检查,如果创建出来的对象,赋值了不相干的对象就会有一个警告信息,防止出错。id类型可以作为形参,也可以作为方法的返回值。
  1. // init此时返回值是id
  2. NSString *str = [[Person alloc] init];
  3. // Person并没有length方法, 但是id是动态类型, 所以编译时不会报错
  4. NSLog(@”length = %i”, str.length);
  5. —————————-
  6. // init此时返回值是instancetype
  7. // 由于instancetype它会进行类型检查, 所以会报警告
  8. NSString *str = [[Person alloc] init];
  9. NSLog(@”length = %i”, str.length);
  10. —————————-
  11. instancetype *p = [[person alloc] init];
  12. // 错误写法instancetype只能作为返回值

21.类的启动过程

21.1.+load方法

  • 在程序启动的时候会加载所有的类和分类,并调用所有类和分类的+load方法(只会调用一次)
  • load方法加载顺序,在运行时会加载到内存中,会先加载父类的load方法,子类的load方法会在所有的父类加载完之后被加载。*后会是子类的load方法。
  • 不管程序运行过程有没有用到这个类,都会调用+load加载
  1. @implementation Person
  2. + (void)load
  3. {
  4. NSLog(@”%s”, __func__);
  5. }
  6. @end
  7. @implementation Student : Person
  8. + (void)load
  9. {
  10. NSLog(@”%s”, __func__);
  11. }
  12. @end
  13. 输出结果:
  14. +[Person load]
  15. +[Student load]

21.2.+initialize

  • 在*次使用某个类时(比如创建对象等),只会调用一次+initialize方法
  • 一个类只会调用一次+initialize方法,先调用父类的,再调用子类的
  • initlalize方法方法是在类或它的子类收到*条消息之前被调用的,这里所指的消息包括实例方法和类方法的调用。也就是说 +initialize 方法是以懒加载的方式被调用的,如果程序一直没有给某个类或它的子类发送消息,那么这个类的 +initialize 方法是永远不会被调用的。那这样设计有什么好处呢?好处是显而易见的,那就是节省系统资源,避免浪费。
  1. @implementation Person
  2. + (void)initialize
  3. {
  4. NSLog(@”%s”, __func__);
  5. }
  6. @end
  7. @implementation Student : Person
  8. + (void)initialize
  9. {
  10. NSLog(@”%s”, __func__);
  11. }
  12. @end
  13. int main(int argc, const char * argv[]) {
  14. Student *stu = [Student new];
  15. return 0;
  16. }
  17. 输出结果:
  18. +[Person initialize]
  19. +[Student initialize]
  • +load 和 +initialize 总结
比较项 +load +initialize
调用时机 被添加到 runtime 时 收到*条消息前,可能永远不调用
调用顺序 父类->子类->分类 父类->子类
调用次数 1次 多次
是否需要显式调用父类实现
是否沿用父类的实现
分类中的实现 类和分类都执行 覆盖类中的方法,只执行分类的实现

22.SEL介绍

22.1.SEL类型

  • SEL类型代表着方法的签名,在类对象的方法列表中存储着该签名与方法代码的对应关系
  • 每个类的方法列表都存储在类对象中
  • 每个方法都有一个与之对应的SEL类型的对象
  • 根据一个SEL对象就可以找到方法的地址,进而调用方法
  • SEL类型的定义
    • typedef struct objc_selector *SEL;
  • 首先把test这个方法名包装成sel类型的数据
  • 根据SEL数据到该类的类对象上去找,对应的方法的代码,如果找到了就执行该代码
  • 如果没有找到根据类对象上的父类的类对象指针,去父类的类对象中查找,如果找到了,则执行父类的代码
  • 如果没有找到,一直像上找,直到基类(NSObject)
  • 如果都没有找到就报错。
  • 注意:
    • 在这个操作过程中有缓存,*次找的时候是一个一个的找,非常耗性能,之后再用到的时候就直接使用。
    • 个人理解在*次查找的时候会速度比较慢,消耗性能,之后在使用的时候应该会先从缓存中进行查找,如果没有,在按照上边的步骤进行查找。找到之后会先缓存,在执行。
  1. Dog *dog=[[Dog alloc] init];
  2. [dog eat];

%title插图%num

22.2.SEL使用

  • 定义普通的变量
    • 如:SEL sel = @selector(show);
  • 作为方法实参与NSObject配合使用
  • 检验对象是否实现了某个方法
    • – (BOOL) respondsToSelector: (SEL)selector 判断实例是否实现这样方法
    • + (BOOL)instancesRespondToSelector:(SEL)aSelector;
  1. BOOL flag;
  2. // [类 respondsToSelector]用于判断是否包含某个类方法
  3. flag = [Person respondsToSelector:@selector(objectFun)]; //NO
  4. flag = [Person respondsToSelector:@selector(classFun)]; //YES
  5. Person *obj = [[Person alloc] init];
  6. // [对象 respondsToSelector]用于判断是否包含某个对象方法
  7. flag = [obj respondsToSelector:@selector(objectFun)]; //YES
  8. flag = [obj respondsToSelector:@selector(classFun)]; //NO
  9. // [类名 instancesRespondToSelector]用于判断是否包含某个对象方法
  10. // instancesRespondToSelectorr只能写在类名后面, 等价于 [对象 respondsToSelector]
  11. flag = [Person instancesRespondToSelector:@selector(objectFun)]; //YES
  12. flag = [Person instancesRespondToSelector:@selector(classFun)]; //NO
  • 让对象执行某个方法
    • – (id)performSelector:(SEL)aSelector;
    • – (id)performSelector:(SEL)aSelector withObject:(id)object;
    • – (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
      • respondsToSelector注意点: 如果是通过一个对象来调用该方法那么会判断该对象有没有实现-号开头的方法,如果是通过类来调用该方法, 那么会判断该类有没有实现+号开头的方法
  1. Person *p = [Person new];
  2. SEL s1 = @selector(objectFun);
  3. [p performSelector:s1];
  4. SEL s2 = @selector(objectFun:);
  5. [p performSelector:s2 withObject:@“seltest”];
  6. SEL s3 = @selector(objectFun:value2:);
  7. [p performSelector:s3 withObject:@“gzs” withObject:@“seltest”];
  8. SEL s4 = @selector(classFun);
  9. [Person performSelector:s4];
  10. SEL s5 = @selector(classFun:);
  11. [Person performSelector:s5 withObject:@“seltest”];
  12. SEL s6 = @selector(classFun:value2:);
  13. [Person performSelector:s6 withObject:@“seltest” withObject:@“seltest2”];
  • 作为方法形参
  1. @implementation Person
  2. - (void)makeObject:(id) obj performSelector:(SEL) selector
  3. {
  4. [obj performSelector:selector];
  5. }
  6. @end
  7. int main(int argc, const char * argv[]) {
  8. Person *p = [Person new];
  9. SEL s1 = @selector(eat);
  10. Dog *d = [Dog new];
  11. [p makeObject:d performSelector:s1];
  12. return 0;
  13. }

22.3.OC方法查找顺序

%title插图%num
  • 1.给实例对象消息的过程(调用对象方法)
    • 根据对象的isA指针去该对象的类方法中查找,如果找到了就执行
    • 如果没有找到,就去该类的父类类对象中查找
    • 如果没有找到就一直往上找,直到根类(NSObject)
    • 如果都没有找到就报错(还有三次挽救的机会)
  • 2.给类对象发送消息(调用类方法)
    • 根据类对象的isA指针去元对象中查找,如果找到了就执行
    • 如果没有找到就去父元对象中查找
    • 如果如果没有找到就一直往上查找,直到根类(NSOject)
    • 如果都没有找到就报错(还有三次挽救的机会)

23.@class使用

23.1.基本概念

  • 作用
    • 可以简单地引用一个类
  • 简单使用
    • @class Dog;
    • 仅仅是告诉编译器:Dog是一个类;并不会包含Dog这个类的所有内容
  • 具体使用
    • 在.h文件中使用@class引用一个类
    • 在.m文件中使用#import包含这个类的.h文件
  • 其它应用场景
    • 对于循环依赖关系来说,比方A类引用B类,同时B类也引用A类
    • 这种嵌套包含的代码编译会报错
  1. #import “B.h”
  2. @interface A : NSObject
  3. {
  4. B *_b;
  5. }
  6. @end
  7. #import “A.h”
  8. @interface B : NSObject
  9. {
  10. A *_a;
  11. }
  12. @end
  • 当使用@class在两个类相互声明,就不会出现编译报错
  1. @class B;
  2. @interface A : NSObject
  3. {
  4. B *_b;
  5. }
  6. @end
  7. @class A;
  8. @interface B : NSObject
  9. {
  10. A *_a;
  11. }
  12. @end

23.2.@class和#import

  • 作用上的区别
    • #import会包含引用类的所有信息(内容),包括引用类的变量和方法
    • @class仅仅是告诉编译器有这么一个类, 具体这个类里有什么信息, 完全不知
  • 效率上的区别
    • 如果有上百个头文件都#import了同一个文件,或者这些文件依次被#import,那么一旦*开始的头文件稍有改动,后面引用到这个文件的所有类都需要重新编译一遍 , 编译效率非常低
    • 相对来讲,使用@class方式就不会出现这种问题了

24.注释和指令

24.1.#pragma mark指令的使用

  • 功能:简单来说就是对代码的分组,方便代码查找和导航用的 它们告诉Xcode编译器,要在编辑器窗格顶部的方法和函数弹出菜单中将代码分隔开。一些类(尤其是一些控制器类)可能很长,方法和函数弹出菜单可以便于代码导航。此时加入#pragma 指令(#pragma是一个编译指令)对代码进行逻辑组织很有效果。
  • 一个类里我们总会有一些方法的功能与性质是相差不多的,你可能会有把方法们分组的想 法。Xcode已经有了类似的支持,它就是 #pragma mark。
    • 分组: #pragma mark 分组(标识)名称
      %title插图%num
    • 分隔线: #pragma mark –
      %title插图%num
    • 分割线加分组: #pragma mark – 分组(标识)名称
      %title插图%num

24.2.其他指令

  • MARK:
  • TODO:
  • FIXME:
  • !!!:
  • ???:
    基本和#pragma mark指令没神马区别,有图有真相。
%title插图%num

25.分类

25.1.什么是分类(Category)

  • Category有很多种翻译: 分类 \ 类别 \ 类目 (一般叫分类)
  • Category是OC特有的语法, 其他语言没有的语法
  • Category的作用
    • 可以在不修改原来类的基础上, 为这个类扩充一些方法
    • 一个庞大的类可以分模块开发
    • 一个庞大的类可以由多个人来编写,更有利于团队合作

25.2.Category的格式

  • 在.h文件中声明类别
    • 1)新添加的方法必须写在 @interface 与 @end之间
    • 2)ClassName 现有类的类名(要为哪个类扩展方法)
    • 3)CategoryName 待声明的类别名称
    • 4)NewMethod 新添加的方法
  1. @interface ClassName (CategoryName)
  2. NewMethod; //在类别中添加方法
  3. //不允许在类别中添加变量
  4. @end
  • 在.m文件中实现类别:
    • 1)新方法的实现必须写在@ implementation与@end之间
    • 2)ClassName 现有类的类名
    • 3)CategoryName 待声明的类别名称
    • 4)NewMethod 新添加的方法的实现
  1. @implementation ClassName(CategoryName)
  2. NewMethod
  3. … …
  4. @end
  • 使用Xcode创建分类
    • command + N创建文件,然后选择本地存储路径。
      %title插图%num
    • 填写分类名称,下一步,然后选择本地存储路径。
      %title插图%num

25.3.分类的使用注意事项

  • 分类只能增加方法, 不能增加成员变量
  1. @interface Person (gz)
  2. {
  3. // 错误写法
  4. // int _age;
  5. }
  6. – (void)eat;
  7. @end
  • 分类中写property只会生成方法声明
  1. @interface Person (gz)
  2. // 只会生成getter/setter方法的声明, 不会生成实现和私有成员变量
  3. @property (nonatomic, assign) int age;
  4. @end
  • 分类可以访问原来类中的成员变量
  1. @interface Person : NSObject
  2. {
  3. int _no;
  4. }
  5. @end
  6. @implementation Person (gz)
  7. – (void)say
  8. {
  9. NSLog(@”%s”, __func__);
  10. // 可以访问原有类中得成员变量
  11. NSLog(@”no = %i”, _no);
  12. }
  13. @end
  • 如果分类和原来类出现同名的方法, 优先调用分类中的方法, 原来类中的方法会被忽略
  1. @implementation Person
  2. – (void)sleep
  3. {
  4. NSLog(@”%s”, __func__);
  5. }
  6. @end
  7. @implementation Person (gz)
  8. – (void)sleep
  9. {
  10. NSLog(@”%s”, __func__);
  11. }
  12. @end
  13. int main(int argc, const char * argv[]) {
  14. Person *p = [[Person alloc] init];
  15. [p sleep];
  16. return 0;
  17. }
  18. 输出结果:
  19. -[Person(gz) sleep]

25.4.分类的编译的顺序

  • 多个分类中有同名方法,则执行*后编译的文件方法
  1. @implementation Person
  2. – (void)sleep
  3. {
  4. NSLog(@”%s”, __func__);
  5. }
  6. @end
  7. @implementation Person (gz)
  8. – (void)sleep
  9. {
  10. NSLog(@”%s”, __func__);
  11. }
  12. @end
  13. @implementation Person (zz)
  14. – (void)sleep
  15. {
  16. NSLog(@”%s”, __func__);
  17. }
  18. @end
  19. int main(int argc, const char * argv[]) {
  20. Person *p = [[Person alloc] init];
  21. [p sleep];
  22. return 0;
  23. }
  24. 输出结果:
  25. -[Person(zz) sleep]
  • 方法调用的优先级(从高到低)
    • 分类(*后参与编译的分类优先)
    • 原来类
    • 父类

25.5类扩展

  • 延展类别又称为扩展(Extendsion),Extension是Category的一个特例
  • 对比分类,类延展只少了个分类的名字,所有又称之为“匿名分类”
  • 可以为某个类扩充一些私有的成员变量和方法
    • 写在.m文件中
    • 英文名是Class Extension
  • 类扩展书写格式
  1. @interface 类名 ()
  2. @end
  • 例子
  1. #import “Person.h”
  2. @interface Person()
  3. // 没在.h文件中声明,属于私有属性
  4. @property (nonatomic, strong) NSArray *array;
  5. // 没在.h文件中声明,属于私有方法
  6. – (void)say;
  7. @end
  8. @implementation Person
  9. – (void)say{
  10. // TODO
  11. }
  12. @end

 

26. Block

26.1.Block介绍

  • Block是iOS中一种比较特殊的数据类型。在java中没有可以与之相对于的语法。如果你有c语言的基础,明白指针的原理,那就感觉容易多了。个人理解Block就是一个指向函数的指针。该指针指向了一块内存,该内存中存储了一段代码,当你需要执行这一段代码块的时候就根据这个指针找到对应的内存地址,然后就可以执行对应的代码。当然这只是简单说明了Block的作用,在实际开发中还是有很多地方需要好好的研究的。比如,block内部引用对象,如何防止循环引用,如何修改block外边的变量,block中内存如何管理等等,想想就崩溃,这是后话。废话不多说,直接看语法。
  • Block是苹果官方特别推荐使用的数据类型, 应用场景比较广泛
    • 动画
    • 多线程
    • 集合遍历
    • 网络请求回调

26.2.block的格式

  • Block的定义格式
  1. 返回值类型 (^block变量名)(形参列表) = ^(形参列表) {
  2. };
%title插图%num
  • block*简单形式
  1. void (^block名)() = ^{代码块;}
  2. 例如:
  3. void (^myBlock)() = ^{ NSLog(@”block”); };
  • block带有参数的block的定义和使用
  1. void (^block名称)(参数列表)
  2. = ^ (参数列表) { // 代码实现; }
  3. 例如:
  4. void (^myBlock)(int) = ^(int num){ NSLog(@”num = %i”, num); };
  • 带有参数和返回值的block
  1. 返回类型 (^block名称)(参数列表)
  2. = ^ (参数列表) { // 代码实现; }
  3. 例如:
  4. int (^myBlock)(int, int) = ^(int num1, int num2){ return num1 + num2; };
  • 调用Block保存的代码
  1. block变量名(实参);
  2. 例如:
  3. // 调用了block的*简单形式
  4. myBlock();
  5. // 调用了带有参数的block
  6. myBlock(10);
  7. // 调用了带有参数和返回值的block
  8. myBlock(10, 20);

要想成功部署和管理私有云或混合云,需要满足哪些要求?

在本文中,将看到成功部署和管理私有云或混合云的这些要求。

(1)使云计算变简单

企业想要采用本地部署的云计算,但是他们不想花几个星期或几个月来开发它们,也不想雇佣一个OpenStack或VMware专家团队。实质上,企业需要与AWS或其他公共云获得相同的点对点配置,但只能使用本地部署的云计算提供的治理,可扩展性能和控制。

私有云和混合云成功的四个关键因素

有三个方面要考虑:

通用易用性-云平台应包含一个直观的用户界面,使*终用户能够开展自助服务,从而减少IT部门的支持负担。然而,自助服务需要管理:系统应该包括工作流管理和基于角色的访问控制(RBAC),因此IT团队可以设置参数,以确保自助服务完全受控,可审计的方式进行。例如,云平台可能需要许可才能在用户创建或在删除虚拟服务器之前或向虚拟服务器添加资源。

部署-云计算软件应该利用包含其自己的虚拟机管理程序的引导系统,并可以安装在服务器上,并在30分钟内启动并运行。预先安装在超级融合平台上的云计算更易于部署。IT管理应该能够通过网络发现虚拟机管理程序或计算节点,然后云端自动出现,因此安装操作系统或虚拟机管理程序没有任何人工参与。

配置和管理-*简单的云计算包括自我发现,自动配置和统一管理。用户界面在云平台之间有很大差异,但*简单的就是允许对所有基础设施组件进行单一视图(甚至跨地理位置),并允许点对点配置。由于运行云计算基本上意味着控制对资源池的访问,云计算的管理系统应该使用基于角色的访问控制(RBAC)来允许管理员控制对服务器,虚拟机,存储资产,网络带宽甚至CPU内核的访问。管理体系越细致,企业就越能够优化资源和控制成本。

例如,一个全面的管理系统应该能够让云计算管理人员要求对一系列用户操作进行审批。每当用户发出影响资源利用率、成本或虚拟服务器或应用程序可用性的请求(如虚拟机创建或销毁,或请求向虚拟机添加CPU、RAM或存储资源)时,管理人员就需要对这些请求进行审批。

(2)可扩展性

企业应该能够利用他们掌握的任何资源来扩展云计算。IT管理人员不应限制购买一定数量的供应商节点进行扩展,而应该能够使用单个服务器或单个磁盘(无论是SATA,SAS,SSD还是NVME接口的)进行扩展。这种灵活性允许组织通过使用现成的资源优化资源,从而*大程度降低成本。

此外,许多公司都有不同地理分布的业务,希望能够使用不同数据中心的资源来扩展云计算,或者希望能够使用多个云。例如,纽约数据中心的管理员可能需要50个附加服务器来扩展,而芝加哥的管理员可能会让这些服务器处于空闲状态。云平台应允许公司在不同地理位置的节点或不同地理位置的类似云平台中进行扩展,所有这些云都通过单个用户界面进行管理。

许多云平台严格限制了可以并入到云中的节点数量。某些平台例如限于32或64个节点。理想的云平台应该允许扩展到数百个节点。

*后,云平台应该结合软件定义的存储,这样可以实现不同类型磁盘的非对称扩展,从而实现*大的扩展灵活性。

(3)灵活性

该平台应该能够在任何服务器,任何存储和任何网络接口上运行。大多数公司都想使用商品化硬件,云计算应该允许这样做。一些公司希望在超融合平台上实现云教育处,而且这也应该是可能的。

(4)更低的总拥有成本

硬件和云计算软件许可证只是云计算总体拥有成本(TCO)的起点,但它们是考虑节省的重要场所。一些云计算软件能够以其他产品的成本的一小部分获得许可,甚至超级融合平台的价格也各不相同。

灵活地使用现有的商品硬件帮助企业优化自己的资源,避免新的资本支出降低成本。例如,如果他们使用软件定义的存储,他们不必购买新的SAN或新硬件来实现云计算。

要考虑的*终TCO领域是专业服务和定制开发。此外,云计算平台提供商之间的定价差异很大。

实现本地部署的云计算有许多途径,目前具有许多不同价格点和功能集的产品。通过关注这些讨论,企业可以找到*适合其需求的云计算。
————————————————

云学习的特征,主要有哪些?

(1)以学习者为主体的学习

云学习以学习者为中心,以学习任务为目标。学习者能够方便快速地构建个人学习环境,控制和管理个人的学习,选择所需要的学习资源和服务。所有的学习资源存放在学习云中,学习者使用简单的接入设备,就可以使用其中的资源,也可以将自己的学习资源放入“云”中,让云存储成为自己大脑的延伸和扩展,并与其它学习者共同分享。

(2)以协作为形式的学习

在云学习中,学习者充分获得了学习的自主性,根据自己的需求选择学习内容,为了达到更好的学习效果、完成既定的学习任务,具有共同学习目标的学习者可以组成一个学习团体进行协作学习,在协作团体内部,成员可以上传自己的资源,发表自己的看法,也可以对其它成员的意见进行修改补充,而且对方会同步的看到,有利于成员之间的互动和协作。学习者通过云终端学习机和学习云实现学生与老师、学生与学生之间的在线互动和离线互动,提高学习效率。另外,来自世界各地、不同国家、不同文化背景的人也可以组建团体共同学习和讨论,分享学习经验和学习资源,共同完成学习任务。

(3)以资源为内容的学习

云计算*大的优势是于资源的聚合。信息的融合、存储通过网络服务进行共享,这使得教育资源*大限度地得到整合。因此,云学习时代是整合学习与教育资源的时代,资源是云学习的核心。来自于世界各地的学习者、指导者、专家、团队、服务商共同组建和开发资源将聚合到“云”端的存储服务器中,学习者通过终端设备自由选择。同时学习者也不用担心海量信息造成知识的拥塞与膨胀,有专业的团队对知识进行分类、屏蔽不良信息、纠正错误信息等,*终构建成一个可以无限扩展的资源网络。