- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章ios开发:一个音乐播放器的设计与实现案例由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
这个demo,关于歌曲播放的主要功能都实现了的。下一曲、上一曲,暂停,根据歌曲的播放进度动态滚动歌词,将当前正在播放的歌词放大显示,拖动进度条,歌曲跟着变化,并且使用time profiler进行了优化,还使用xctest对几个主要的类进行了单元测试.
已经经过真机调试,在真机上可以后台播放音乐,并且锁屏时,显示一些主要的歌曲信息.
根据歌曲的播放来显示对应歌词的。用uitableview来显示歌词,可以手动滚动界面查看后面或者前面的歌词.
并且,当拖动进度条,歌词也会随之变化,下一曲、上一曲依然是可以使用的.
代码分析:
准备阶段,先是写了一个音频播放的单例,用这个单例来播放这个demo中的音乐文件,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
#import <foundation/foundation.h>
#import <avfoundation/avfoundation.h>
@interface zyaudiomanager : nsobject
+ (instancetype)defaultmanager;
//播放音乐
- (avaudioplayer *)playingmusic:(nsstring *)filename;
- (
void
)pausemusic:(nsstring *)filename;
- (
void
)stopmusic:(nsstring *)filename;
//播放音效
- (
void
)playsound:(nsstring *)filename;
- (
void
)disposesound:(nsstring *)filename;
@end
#import "zyaudiomanager.h"
@interface zyaudiomanager ()
@property (nonatomic, strong) nsmutabledictionary *musicplayers;
@property (nonatomic, strong) nsmutabledictionary *soundids;
@end
static
zyaudiomanager *_instance = nil;
@implementation zyaudiomanager
+ (
void
)initialize
{
// 音频会话
avaudiosession *session = [avaudiosession sharedinstance];
// 设置会话类型(播放类型、播放模式,会自动停止其他音乐的播放)
[session setcategory:avaudiosessioncategoryplayback error:nil];
// 激活会话
[session setactive:yes error:nil];
}
+ (instancetype)defaultmanager
{
static
dispatch_once_t oncetoken;
dispatch_once(&oncetoken, ^{
_instance = [[self alloc] init];
});
return
_instance;
}
- (instancetype)init
{
__block zyaudiomanager *temp = self;
static
dispatch_once_t oncetoken;
dispatch_once(&oncetoken, ^{
if
((temp = [super init]) != nil) {
_musicplayers = [nsmutabledictionary dictionary];
_soundids = [nsmutabledictionary dictionary];
}
});
self = temp;
return
self;
}
+ (instancetype)allocwithzone:(
struct
_nszone *)zone
{
static
dispatch_once_t oncetoken;
dispatch_once(&oncetoken, ^{
_instance = [super allocwithzone:zone];
});
return
_instance;
}
//播放音乐
- (avaudioplayer *)playingmusic:(nsstring *)filename
{
if
(filename == nil || filename.length == 0)
return
nil;
avaudioplayer *player = self.musicplayers[filename];
//先查询对象是否缓存了
if
(!player) {
nsurl *url = [[nsbundle mainbundle] urlforresource:filename withextension:nil];
if
(!url)
return
nil;
player = [[avaudioplayer alloc] initwithcontentsofurl:url error:nil];
if
(![player preparetoplay])
return
nil;
self.musicplayers[filename] = player;
//对象是最新创建的,那么对它进行一次缓存
}
if
(![player isplaying]) {
//如果没有正在播放,那么开始播放,如果正在播放,那么不需要改变什么
[player play];
}
return
player;
}
- (
void
)pausemusic:(nsstring *)filename
{
if
(filename == nil || filename.length == 0)
return
;
avaudioplayer *player = self.musicplayers[filename];
if
([player isplaying]) {
[player pause];
}
}
- (
void
)stopmusic:(nsstring *)filename
{
if
(filename == nil || filename.length == 0)
return
;
avaudioplayer *player = self.musicplayers[filename];
[player stop];
[self.musicplayers removeobjectforkey:filename];
}
//播放音效
- (
void
)playsound:(nsstring *)filename
{
if
(!filename)
return
;
//取出对应的音效id
systemsoundid soundid = (
int
)[self.soundids[filename] unsignedlongvalue];
if
(!soundid) {
nsurl *url = [[nsbundle mainbundle] urlforresource:filename withextension:nil];
if
(!url)
return
;
audioservicescreatesystemsoundid((__bridge cfurlref)(url), &soundid);
self.soundids[filename] = @(soundid);
}
// 播放
audioservicesplaysystemsound(soundid);
}
//摧毁音效
- (
void
)disposesound:(nsstring *)filename
{
if
(!filename)
return
;
systemsoundid soundid = (
int
)[self.soundids[filename] unsignedlongvalue];
if
(soundid) {
audioservicesdisposesystemsoundid(soundid);
[self.soundids removeobjectforkey:filename];
//音效被摧毁,那么对应的对象应该从缓存中移除
}
}
@end
|
就是一个单例的设计,并没有多大难度。我是用了一个字典来装播放过的歌曲了,这样如果是暂停了,然后再开始播放,就直接在缓存中加载即可。但是如果不注意,在 stopmusic:(nsstring *)filename 这个方法里面,不从字典中移除掉已经停止播放的歌曲,那么你下再播放这首歌的时候,就会在原先播放的进度上继续播放。在编码过程中,我就遇到了这个bug,然后发现,在切换歌曲(上一曲、下一曲)的时候,我调用的是stopmusic方法,但由于我没有从字典中将它移除,而导致它总是从上一次的进度开始播放,而不是从头开始播放.
如果在真机上想要后台播放歌曲,除了在appdelegate以及plist里面做相应操作之外,还得将播放模式设置为:avaudiosessioncategoryplayback。特别需要注意这里,我在模拟器上调试的时候,没有设置这种模式也是可以进行后台播放的,但是在真机上却不行了。后来在stackoverflow上找到了对应的答案,需要设置播放模式.
这个单例类,在整个demo中是至关重要的,要保证它是没有错误的,所以我写了这个类的xctest进行单元测试,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
#import <xctest/xctest.h>
#import "zyaudiomanager.h"
#import <avfoundation/avfoundation.h>
@interface zyaudiomanagertests : xctestcase
@property (nonatomic, strong) avaudioplayer *player;
@end
static
nsstring *_filename = @
"10405520.mp3"
;
@implementation zyaudiomanagertests
- (
void
)setup {
[super setup];
// put setup code here. this method is called before the invocation of each test method in the class.
}
- (
void
)teardown {
// put teardown code here. this method is called after the invocation of each test method in the class.
[super teardown];
}
- (
void
)testexample {
// this is an example of a functional test case.
// use xctassert and related functions to verify your tests produce the correct results.
}
/**
* 测试是否为单例,要在并发条件下测试
*/
- (
void
)testaudiomanagersingle
{
nsmutablearray *managers = [nsmutablearray array];
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(dispatch_queue_priority_default, 0), ^{
zyaudiomanager *tempmanager = [[zyaudiomanager alloc] init];
[managers addobject:tempmanager];
});
dispatch_group_async(group, dispatch_get_global_queue(dispatch_queue_priority_default, 0), ^{
zyaudiomanager *tempmanager = [[zyaudiomanager alloc] init];
[managers addobject:tempmanager];
});
dispatch_group_async(group, dispatch_get_global_queue(dispatch_queue_priority_default, 0), ^{
zyaudiomanager *tempmanager = [[zyaudiomanager alloc] init];
[managers addobject:tempmanager];
});
dispatch_group_async(group, dispatch_get_global_queue(dispatch_queue_priority_default, 0), ^{
zyaudiomanager *tempmanager = [[zyaudiomanager alloc] init];
[managers addobject:tempmanager];
});
dispatch_group_async(group, dispatch_get_global_queue(dispatch_queue_priority_default, 0), ^{
zyaudiomanager *tempmanager = [[zyaudiomanager alloc] init];
[managers addobject:tempmanager];
});
zyaudiomanager *managerone = [zyaudiomanager defaultmanager];
dispatch_group_notify(group, dispatch_get_global_queue(dispatch_queue_priority_default, 0), ^{
[managers enumerateobjectsusingblock:^(zyaudiomanager *obj, nsuinteger idx,
bool
* _nonnull stop) {
xctassertequal(managerone, obj, @
"zyaudiomanager is not single"
);
}];
});
}
/**
* 测试是否可以正常播放音乐
*/
- (
void
)testplayingmusic
{
self.player = [[zyaudiomanager defaultmanager] playingmusic:_filename];
xctasserttrue(self.player.playing, @
"zyaudiomanager is not playingmusic"
);
}
/**
* 测试是否可以正常停止音乐
*/
- (
void
)teststopmusic
{
if
(self.player == nil) {
self.player = [[zyaudiomanager defaultmanager] playingmusic:_filename];
}
if
(self.player.playing == no) [self.player play];
[[zyaudiomanager defaultmanager] stopmusic:_filename];
xctassertfalse(self.player.playing, @
"zyaudiomanager is not stopmusic"
);
}
/**
* 测试是否可以正常暂停音乐
*/
- (
void
)testpausemusic
{
if
(self.player == nil) {
self.player = [[zyaudiomanager defaultmanager] playingmusic:_filename];
}
if
(self.player.playing == no) [self.player play];
[[zyaudiomanager defaultmanager] pausemusic:_filename];
xctassertfalse(self.player.playing, @
"zyaudiomanager is not pausemusic"
);
}
@end
|
需要注意的是,单例要在并发的条件下测试,我采用的是dispatch_group,主要是考虑到,必须要等待所有并发结束才能比较结果,否则可能会出错。比如说,并发条件下,x线程已经执行完毕了,它所对应的a对象已有值;而y线程还没开始初始化,它所对应的b对象还是为nil,为了避免这种条件的产生,我采用dispatch_group来等待所有并发结束,再去做相应的判断.
首页控制器的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
#import "zymusicviewcontroller.h"
#import "zyplayingviewcontroller.h"
#import "zymusictool.h"
#import "zymusic.h"
#import "zymusiccell.h"
@interface zymusicviewcontroller ()
@property (nonatomic, strong) zyplayingviewcontroller *playingvc;
@property (nonatomic, assign)
int
currentindex;
@end
@implementation zymusicviewcontroller
- (zyplayingviewcontroller *)playingvc
{
if
(_playingvc == nil) {
_playingvc = [[zyplayingviewcontroller alloc] initwithnibname:@
"zyplayingviewcontroller"
bundle:nil];
}
return
_playingvc;
}
- (
void
)viewdidload {
[super viewdidload];
[self setupnavigation];
}
- (
void
)setupnavigation
{
self.navigationitem.title = @
"音乐播放器"
;
}
#pragma mark ----tableviewdatasource
- (nsinteger)numberofsectionsintableview:(uitableview *)tableview {
return
1;
}
- (nsinteger)tableview:(uitableview *)tableview numberofrowsinsection:(nsinteger)section {
return
[zymusictool musics].count;
}
- (uitableviewcell *)tableview:(uitableview *)tableview cellforrowatindexpath:(nsindexpath *)indexpath
{
zymusiccell *cell = [zymusiccell musiccellwithtableview:tableview];
cell.music = [zymusictool musics][indexpath.row];
return
cell;
}
#pragma mark ----tableviewdelegate
- (cgfloat)tableview:(uitableview *)tableview heightforrowatindexpath:(nsindexpath *)indexpath
{
return
70;
}
- (
void
)tableview:(uitableview *)tableview didselectrowatindexpath:(nsindexpath *)indexpath
{
[tableview deselectrowatindexpath:indexpath animated:yes];
[zymusictool setplayingmusic:[zymusictool musics][indexpath.row]];
zymusic *premusic = [zymusictool musics][self.currentindex];
premusic.playing = no;
zymusic *music = [zymusictool musics][indexpath.row];
music.playing = yes;
nsarray *indexpaths = @[
[nsindexpath indexpathforitem:self.currentindex insection:0],
indexpath
];
[self.tableview reloadrowsatindexpaths:indexpaths withrowanimation:uitableviewrowanimationnone];
self.currentindex = (
int
)indexpath.row;
[self.playingvc show];
}
@end
|
重点需要说说的是这个界面的实现: 这里做了比较多的细节控制,具体在代码里面有相应的描述。主要是想说说,在实现播放进度拖拽中遇到的问题.
控制进度条的移动,我采用的是nstimer,添加了一个定时器,并且在不需要它的地方都做了相应的移除操作.
这里开发的时候,遇到了一个问题是,我拖动滑块的时候,发现歌曲播放的进度是不正确的。代码中可以看到:
1
2
3
4
|
//得到挪动距离
cgpoint point = [sender translationinview:sender.view];
//将translation清空,免得重复叠加
[sender settranslation:cgpointzero inview:sender.view];
|
在使用translation的时候,一定要记住,每次处理过后,一定要将translation清空,以免它不断叠加.
我使用的是zylrcview来展示歌词界面的,需要注意的是,它继承自uiimageview,所以要将userinteractionenabled属性设置为yes.
代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
#import <uikit/uikit.h>
@interface zylrcview : uiimageview
@property (nonatomic, assign) nstimeinterval currenttime;
@property (nonatomic, copy) nsstring *filename;
@end
#import "zylrcview.h"
#import "zylrcline.h"
#import "zylrccell.h"
#import "uiview+autolayout.h"
@interface zylrcview () <uitableviewdatasource, uitableviewdelegate>
@property (nonatomic, weak) uitableview *tableview;
@property (nonatomic, strong) nsmutablearray *lrclines;
/**
* 记录当前显示歌词在数组里面的index
*/
@property (nonatomic, assign)
int
currentindex;
@end
@implementation zylrcview
#pragma mark ----setter\geter方法
- (nsmutablearray *)lrclines
{
if
(_lrclines == nil) {
_lrclines = [zylrcline lrclineswithfilename:self.filename];
}
return
_lrclines;
}
- (
void
)setfilename:(nsstring *)filename
{
if
([_filename isequaltostring:filename]) {
return
;
}
_filename = [filename copy];
[_lrclines removeallobjects];
_lrclines = nil;
[self.tableview reloaddata];
}
- (
void
)setcurrenttime:(nstimeinterval)currenttime
{
if
(_currenttime > currenttime) {
self.currentindex = 0;
}
_currenttime = currenttime;
int
minute = currenttime / 60;
int
second = (
int
)currenttime % 60;
int
msecond = (currenttime - (
int
)currenttime) * 100;
nsstring *currenttimestr = [nsstring stringwithformat:@
"%02d:%02d.%02d"
, minute, second, msecond];
for
(
int
i = self.currentindex; i < self.lrclines.count; i++) {
zylrcline *currentline = self.lrclines[i];
nsstring *currentlinetime = currentline.
time
;
nsstring *nextlinetime = nil;
if
(i + 1 < self.lrclines.count) {
zylrcline *nextline = self.lrclines[i + 1];
nextlinetime = nextline.
time
;
}
if
(([currenttimestr compare:currentlinetime] != nsorderedascending) && ([currenttimestr compare:nextlinetime] == nsorderedascending) && (self.currentindex != i)) {
nsarray *reloadlines = @[
[nsindexpath indexpathforitem:self.currentindex insection:0],
[nsindexpath indexpathforitem:i insection:0]
];
self.currentindex = i;
[self.tableview reloadrowsatindexpaths:reloadlines withrowanimation:uitableviewrowanimationnone];
[self.tableview scrolltorowatindexpath:[nsindexpath indexpathforitem:self.currentindex insection:0] atscrollposition:uitableviewscrollpositiontop animated:yes];
}
}
}
#pragma mark ----初始化方法
- (instancetype)initwithframe:(cgrect)frame
{
if
(self = [super initwithframe:frame]) {
[self commitinit];
}
return
self;
}
- (instancetype)initwithcoder:(nscoder *)adecoder
{
if
(self = [super initwithcoder:adecoder]) {
[self commitinit];
}
return
self;
}
- (
void
)commitinit
{
self.userinteractionenabled = yes;
self.image = [uiimage imagenamed:@
"28131977_1383101943208"
];
self.contentmode = uiviewcontentmodescaletofill;
self.clipstobounds = yes;
uitableview *tableview = [[uitableview alloc] init];
tableview.delegate = self;
tableview.datasource = self;
tableview.separatorstyle = uitableviewcellseparatorstylenone;
tableview.backgroundcolor = [uicolor clearcolor];
self.tableview = tableview;
[self addsubview:tableview];
[self.tableview autopinedgestosuperviewedgeswithinsets:uiedgeinsetsmake(0, 0, 0, 0)];
}
#pragma mark ----uitableviewdatasource
- (nsinteger)numberofsectionsintableview:(uitableview *)tableview
{
return
1;
}
- (nsinteger)tableview:(uitableview *)tableview numberofrowsinsection:(nsinteger)section
{
return
self.lrclines.count;
}
- (uitableviewcell *)tableview:(uitableview *)tableview cellforrowatindexpath:(nsindexpath *)indexpath
{
zylrccell *cell = [zylrccell lrccellwithtableview:tableview];
cell.lrcline = self.lrclines[indexpath.row];
if
(indexpath.row == self.currentindex) {
cell.textlabel.font = [uifont boldsystemfontofsize:16];
}
else
{
cell.textlabel.font = [uifont systemfontofsize:13];
}
return
cell;
}
- (
void
)layoutsubviews
{
[super layoutsubviews];
// nslog(@"++++++++++%@",nsstringfromcgrect(self.tableview.frame));
self.tableview.contentinset = uiedgeinsetsmake(self.frame.size.height / 2, 0, self.frame.size.height / 2, 0);
}
@end
|
也没有什么好说的,整体思路就是,解析歌词,将歌词对应的播放时间、在当前播放时间的那句歌词一一对应,然后持有一个歌词播放的定时器,每次给zylrcview传入歌曲播放的当前时间,如果,歌曲的currenttime > 当前歌词的播放,并且小于下一句歌词的播放时间,那么就是播放当前的这一句歌词了.
我这里做了相应的优化,cadisplaylink生成的定时器,是每毫秒调用触发一次,1s等于1000ms,如果不做一定的优化,性能是非常差的,毕竟一首歌怎么也有四五分钟。在这里,我记录了上一句歌词的index,那么如果正常播放的话,它去查找歌词应该是从上一句播放的歌词在数组里面的索引开始查找,这样就优化了很多.
这是锁屏下的界面展示: 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我.
最后此篇关于ios开发:一个音乐播放器的设计与实现案例的文章就讲到这里了,如果你想了解更多关于ios开发:一个音乐播放器的设计与实现案例的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我需要一些说明。我可以直接写入 /dev/port 以直接访问并行端口并且它工作正常(我可以打开插入端口连接器的 LED)。但是,我想我可以用 /dev/mem 做同样的事情? (http://tld
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我使用 Visual C++ 和 Win32 API 学习了 Windows 编程。如今,似乎大多数应用程序都是使用 C# 在 .NET 中开发的。我知道大多数时候 native 代码和托管代码之间没
请耐心等待。我正在制作一个 java 控制台,类似于此处找到的 DragonConsole https://code.google.com/p/dragonconsole/ 。一切都按计划进行,但我想
关闭。这个问题需要更多 focused .它目前不接受答案。 想要改进这个问题吗? 更新问题,使其只关注一个问题 editing this post . 关闭5年前。 Improve this que
Django 的开发服务器表现得很奇怪。访问它的浏览器在加载时卡住,任何退出它的尝试都不起作用。当我点击 control c看似相当,但实际上仍在运行。让它退出的唯一方法是重新启动我的电脑,这很令人沮
我正在使用 Flash Develop,并且创建了一个 ActionScript 3.0 项目。它启动并读取一个 xml 文件,其中包含图像的 url。我已将 url 保留在与 swf 相同的文件夹中
是否可以根据其 website 上提供的规范开发 AUTOSAR BSW 堆栈(例如用于 CAN 通信)?不购买任何昂贵的供应商工具?可以遵循哪些步骤?我被要求探索这种可能性。 最佳答案 是和否。工具
有人知道如何用音频文件的内容覆盖 iPhone 麦克风吗? 想象一个场景,您正在通话,并且想要播放一些简短的音频让其他人听到。 因此,有必要将麦克风(硬件)置于保持状态,并使用委托(delegate)
我遇到了这个问题,我的应用程序出现 EXC_BAD_ACCESS 错误并卡住/停止。我使用模拟器的“向左旋转”和“向右旋转”选项来模拟方向变化行为。导致此错误的可能原因有哪些?由于我没有获得有关错误的
我有超过 1 台 Mac,我想在所有这些 Mac 上进行开发。我知道我需要在每台机器上同步我的手机,但这是我遇到的最小的问题。看起来我无法在手机上运行应用程序,除了在其中之一上开发的应用程序。 是否有
在手机上测试时,我的应用程序在特定点崩溃。控制台显示此消息 Tue Jan 27 15:47:14 unknown SpringBoard[22] : Application com.myprof.
我有一个案例,我从服务器获取信息。我的应用程序有一个选项卡栏和导航按钮。我希望应用程序显示进度指示器并禁用所有其他控件,以便用户在从服务器提取数据时无法跳转。我怎样才能实现这个目标? 我想到的一种方法
有时,当我尝试“构建”/编译下载的源代码时,我会收到以下警告: ld: warning: directory '/Volumes/Skiiing2/CD/ViewBased/Unknown Path/
我无法在 Apple 文档中找到关于开发和分发配置之间差异的明确解释。我目前正在使用开发配置在我的 iPhone 上进行开发和测试。我打算将该应用程序分发到我的 Beta 测试中,我想知道: 我需要使
我在使用 SharePoint 时遇到的最大挑战之一是它不能很好地适应典型的项目环境,其中至少包含开发和生产环境。我遇到的最多的问题是内容和列表是如此紧密地耦合在一起,以至于如果不在生产环境中执行内容
我失败了fist step让 Eclipse(对我来说是全新的)为 ARM 开发做好准备。 我在 Windows 10 中安装了 Eclipse。我想我应该安装 xpm,但我不知道在哪里输入此命令:
首先,我告诉你-我是编码新手 我正在使用vs代码来学习c++,它不会产生像dev c++或codeblocks这样的调试器。我看了一些视频,其中我们必须编辑json文件,这对于初学者来说非常复杂。有人
我失败了fist step让 Eclipse(对我来说是全新的)为 ARM 开发做好准备。 我在 Windows 10 中安装了 Eclipse。我想我应该安装 xpm,但我不知道在哪里输入此命令:
我开发了一个 Ionic 应用程序(iOS 和 Android 的混合)。我有 Xcode 8.3.3 并购买了一年的 Apple Developer Program 订阅。 我不想测试我的应用并将其
我是一名优秀的程序员,十分优秀!