iOS 多線程實(shí)現(xiàn)小結(jié)

簡(jiǎn)介

在iOS中厨喂,我們需要將非UI且耗時(shí)的任務(wù)放在主線程當(dāng)中執(zhí)行蜕煌,同時(shí)確保在任務(wù)完成時(shí)進(jìn)行回調(diào)斜纪。常用的三種實(shí)現(xiàn)多線程方式如下:

1. GCD

2. NSThread

3. NSOperation / NSOperationQueue

先就GCD小結(jié)下盒刚。

小結(jié)分析

下面分別予以簡(jiǎn)單小結(jié)因块。

一 GCD

GCD 是Grand Central Dispatch的縮寫籍铁,是蘋果提供的基于block回調(diào)的多線程實(shí)現(xiàn)方式。

GCD維護(hù)線程的創(chuàng)建和調(diào)度及生命周期芋酌,程序員只需負(fù)責(zé)進(jìn)行業(yè)務(wù)邏輯的處理脐帝。

GCD有異步和同步執(zhí)行任務(wù)兩種處理方式.使用時(shí)腮恩,無(wú)須關(guān)心隊(duì)列和任務(wù)的調(diào)度温兼,由系統(tǒng)負(fù)責(zé)安排募判。相應(yīng)的API函數(shù)定義在dispatch/queue.h當(dāng)中届垫。

根據(jù)該文檔中的注釋:

Dispatch is an abstract model for expressing concurrency via simple but

powerful API.

*

* At the core, dispatch provides serial FIFO queues to which blocks may be

* submitted. Blocks submitted to these dispatch queues are invoked on a pool

* of threads fully managed by the system. No guarantee is made regarding

* which thread a block will be invoked on; however, it is guaranteed that only

* one block submitted to the FIFO dispatch queue will be invoked at a time.

*

* When multiple queues have blocks to be processed, the system is free to

* allocate additional threads to invoke the blocks concurrently. When the

* queues become empty, these threads are automatically released.


/*!

* @typedef dispatch_queue_t

*

* @abstract

* Dispatch queues invoke blocks submitted to them serially in FIFO order. A

* queue will only invoke one block at a time, but independent queues may each

* invoke their blocks concurrently with respect to each other.

*

* @discussion

* Dispatch queues are lightweight objects to which blocks may be submitted.

* The system manages a pool of threads which process dispatch queues and

* invoke blocks submitted to them.

*

* Conceptually a dispatch queue may have its own thread of execution, and

* interaction between queues is highly asynchronous.

*

* Dispatch queues are reference counted via calls to dispatch_retain() and

* dispatch_release(). Pending blocks submitted to a queue also hold a

* reference to the queue until they have finished. Once all references to a

* queue have been released, the queue will be deallocated by the system.

*/

系統(tǒng)維護(hù)一個(gè)FIFO(先進(jìn)先出順序)的隊(duì)列误债,提交到隊(duì)列中的block任務(wù)由系統(tǒng)負(fù)責(zé)分配線程執(zhí)行寝蹈,但不能保證哪個(gè)線程會(huì)執(zhí)行登淘,且多個(gè)線程中只有一個(gè)保證在執(zhí)行黔州。當(dāng)系統(tǒng)中線程數(shù)不夠時(shí)流妻,將自動(dòng)創(chuàng)建線程绅这。block為空時(shí),對(duì)應(yīng)的線程會(huì)自動(dòng)被銷毀峭判。

dispatch通過(guò)dispatch_retain() 和dispatch_release()來(lái)進(jìn)行引用記數(shù)管理林螃。

(一)GCD的調(diào)用:

1.異步調(diào)用:

1.1?

void dispatch_async(dispatch_queue_tqueue,dispatch_block_tblock);

調(diào)用之后疗认,會(huì)立即返回横漏,不等待提交的block執(zhí)行完成缎浇。

1.2

void dispatch_async_f(dispatch_queue_tqueue,

void*context,

dispatch_function_twork);

/*!

* @function dispatch_async_f

*

* @abstract

* Submits a function for asynchronous execution on a dispatch queue.

*

* @discussion

* See dispatch_async() for details.

*

* @param queue

* The target dispatch queue to which the function is submitted.

* The system will hold a reference on the target queue until the function

* has returned.

* The result of passing NULL in this parameter is undefined.

*

* @param context

* The application-defined context parameter to pass to the function.

*

* @param work

* The application-defined function to invoke on the target queue. The first

* parameter passed to this function is the context provided to

* dispatch_async_f().

* The result of passing NULL in this parameter is undefined.

*/

__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)

DISPATCH_EXPORTDISPATCH_NONNULL1DISPATCH_NONNULL3DISPATCH_NOTHROW

void

dispatch_async_f(dispatch_queue_tqueue,

void*context,

dispatch_function_twork);

context可以傳0或Nsnull素跺,詳見(jiàn)How to use dispatch_async_f

2. 同步調(diào)用:

2.1 void dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);

將block中的任務(wù)執(zhí)行完成后才會(huì)返回指厌。通常用于設(shè)置和與服務(wù)器同步踩验,等待設(shè)置完成和服務(wù)器返回后才進(jìn)行下一步操作箕憾。

/*!

* @function dispatch_sync

*

* @abstract

* Submits a block for synchronous execution on a dispatch queue.

*

* @discussion

* Submits a block to a dispatch queue like dispatch_async(), however

* dispatch_sync() will not return until the block has finished.

*

* Calls to dispatch_sync() targeting the current queue will result

* in dead-lock. Use of dispatch_sync() is also subject to the same

* multi-party dead-lock problems that may result from the use of a mutex.

* Use of dispatch_async() is preferred.

*

* Unlike dispatch_async(), no retain is performed on the target queue. Because

* calls to this function are synchronous, the dispatch_sync() "borrows" the

* reference of the caller.

*

* As an optimization, dispatch_sync() invokes the block on the current

* thread when possible.

*

* @param queue

* The target dispatch queue to which the block is submitted.

* The result of passing NULL in this parameter is undefined.

*

* @param block

* The block to be invoked on the target dispatch queue.

* The result of passing NULL in this parameter is undefined.

*/

#ifdef __BLOCKS__

__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)

DISPATCH_EXPORT DISPATCH_NONNULL_ALL DISPATCH_NOTHROW

void

dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);

#endif

2.2 void dispatch_sync_f(dispatch_queue_t queue,

void *context,

dispatch_function_t work);

/*!

* @function dispatch_sync_f

*

* @abstract

* Submits a function for synchronous execution on a dispatch queue.

*

* @discussion

* See dispatch_sync() for details.

*

* @param queue

* The target dispatch queue to which the function is submitted.

* The result of passing NULL in this parameter is undefined.

*

* @param context

* The application-defined context parameter to pass to the function.

*

* @param work

* The application-defined function to invoke on the target queue. The first

* parameter passed to this function is the context provided to

* dispatch_sync_f().

* The result of passing NULL in this parameter is undefined.

*/

__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)

DISPATCH_EXPORT DISPATCH_NONNULL1 DISPATCH_NONNULL3 DISPATCH_NOTHROW

void

dispatch_sync_f(dispatch_queue_t queue,

void *context,

dispatch_function_t work);

3. 多次調(diào)用

3.1 void dispatch_apply(size_titerations,dispatch_queue_tqueue, void(^block)(size_t));

函數(shù)原型如下:

/*!

* @function dispatch_apply

*

* @abstract

* Submits a block to a dispatch queue for multiple invocations.

*

* @discussion

* Submits a block to a dispatch queue for multiple invocations. This function

* waits for the task block to complete before returning. If the target queue

* is concurrent, the block may be invoked concurrently, and it must therefore

* be reentrant safe.

*

* Each invocation of the block will be passed the current index of iteration.

*

* @param iterations

* The number of iterations to perform.

*

* @param queue

* The target dispatch queue to which the block is submitted.

* The result of passing NULL in this parameter is undefined.

*

* @param block

* The block to be invoked the specified number of iterations.

* The result of passing NULL in this parameter is undefined.

*/

#ifdef __BLOCKS__

__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)

DISPATCH_EXPORTDISPATCH_NONNULL3DISPATCH_NOTHROW

void

dispatch_apply(size_titerations,dispatch_queue_tqueue,

void(^block)(size_t));

#endif

3.2 void dispatch_apply_f(size_titerations,dispatch_queue_tqueue,

void*context,

void(*work)(void*,size_t));

/*!

* @function dispatch_apply_f

*

* @abstract

* Submits a function to a dispatch queue for multiple invocations.

*

* @discussion

* See dispatch_apply() for details.

*

* @param iterations

* The number of iterations to perform.

*

* @param queue

* The target dispatch queue to which the function is submitted.

* The result of passing NULL in this parameter is undefined.

*

* @param context

* The application-defined context parameter to pass to the function.

*

* @param work

* The application-defined function to invoke on the target queue. The first

* parameter passed to this function is the context provided to

* dispatch_apply_f(). The second parameter passed to this function is the

* current index of iteration.

* The result of passing NULL in this parameter is undefined.

*/

__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)

DISPATCH_EXPORTDISPATCH_NONNULL4DISPATCH_NOTHROW

void

dispatch_apply_f(size_titerations,dispatch_queue_tqueue,

void*context,

void(*work)(void*,size_t));

(二)GCD的隊(duì)列

GCD中有3個(gè)隊(duì)列:

2.1 主隊(duì)列

dispatch_get_main_queue(void)

主隊(duì)列一般進(jìn)行UI線程操作,及與用戶交互刻像。因此细睡,對(duì)于長(zhǎng)時(shí)間的復(fù)雜邏輯處理任務(wù),一般都將放到后臺(tái)隊(duì)列當(dāng)中進(jìn)行犀填。為了操作流暢和用戶體驗(yàn)九巡,網(wǎng)絡(luò)請(qǐng)求及數(shù)據(jù)庫(kù)操作等任務(wù)蹂季,都不要在主隊(duì)列當(dāng)中進(jìn)行偿洁。

/*!

* @function dispatch_get_main_queue

*

* @abstract

* Returns the default queue that is bound to the main thread.

*

* @discussion

* In order to invoke blocks submitted to the main queue, the application must

* call dispatch_main(), NSApplicationMain(), or use a CFRunLoop on the main

* thread.

*

* @result

* Returns the main queue. This queue is created automatically on behalf of

* the main thread before main() is called.

*/

DISPATCH_INLINE DISPATCH_ALWAYS_INLINE DISPATCH_CONST DISPATCH_NOTHROW

dispatch_queue_t

dispatch_get_main_queue(void)

{

return DISPATCH_GLOBAL_OBJECT(dispatch_queue_t, _dispatch_main_q);

}

2.2 串行隊(duì)列

創(chuàng)建:

dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);

/*!

* @function dispatch_queue_create

*

* @abstract

* Creates a new dispatch queue to which blocks may be submitted.

*

* @discussion

* Dispatch queues created with the DISPATCH_QUEUE_SERIAL or a NULL attribute

* invoke blocks serially in FIFO order.

*

* Dispatch queues created with the DISPATCH_QUEUE_CONCURRENT attribute may

* invoke blocks concurrently (similarly to the global concurrent queues, but

* potentially with more overhead), and support barrier blocks submitted with

* the dispatch barrier API, which e.g. enables the implementation of efficient

* reader-writer schemes.

*

* When a dispatch queue is no longer needed, it should be released with

* dispatch_release(). Note that any pending blocks submitted to a queue will

* hold a reference to that queue. Therefore a queue will not be deallocated

* until all pending blocks have finished.

*

* Passing the result of the dispatch_queue_attr_make_with_qos_class() function

* to the attr parameter of this function allows a quality of service class and

* relative priority to be specified for the newly created queue.

* The quality of service class so specified takes precedence over the quality

* of service class of the newly created dispatch queue's target queue (if any)

* as long that does not result in a lower QOS class and relative priority.

*

* When no quality of service class is specified, the target queue of a newly

* created dispatch queue is the default priority global concurrent queue.

*

* @param label

* A string label to attach to the queue.

* This parameter is optional and may be NULL.

*

* @param attr

* DISPATCH_QUEUE_SERIAL, DISPATCH_QUEUE_CONCURRENT, or the result of a call to

* the function dispatch_queue_attr_make_with_qos_class().

*

* @result

* The newly created dispatch queue.

*/

__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)

DISPATCH_EXPORT DISPATCH_MALLOC DISPATCH_RETURNS_RETAINED DISPATCH_WARN_RESULT

DISPATCH_NOTHROW

dispatch_queue_t

dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);

獲取指定label的隊(duì)列:

const char *dispatch_queue_get_label(dispatch_queue_t queue);

/*!

* @function dispatch_queue_get_label

*

* @abstract

* Returns the label of the given queue, as specified when the queue was

* created, or the empty string if a NULL label was specified.

*

* Passing DISPATCH_CURRENT_QUEUE_LABEL will return the label of the current

* queue.

*

* @param queue

* The queue to query, or DISPATCH_CURRENT_QUEUE_LABEL.

*

* @result

* The label of the queue.

*/

__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)

DISPATCH_EXPORT DISPATCH_PURE DISPATCH_WARN_RESULT DISPATCH_NOTHROW

const char *

dispatch_queue_get_label(dispatch_queue_t queue);

2.3 全局隊(duì)列

dispatch_get_global_queue(long identifier, unsigned long flags);

identifier表示優(yōu)先級(jí):有四個(gè)值:

DISPATCH_QUEUE_PRIORITY_HIGH:? ? ? ? 高優(yōu)先級(jí)宾肺,一般是需要處理的緊急任務(wù)或UI線程

?DISPATCH_QUEUE_PRIORITY_DEFAULT: ? ? ?默認(rèn)優(yōu)先級(jí)

DISPATCH_QUEUE_PRIORITY_LOW: ? ? ? ? ?低優(yōu)先級(jí)

?DISPATCH_QUEUE_PRIORITY_BACKGROUND:后臺(tái)進(jìn)程爱榕,比如網(wǎng)絡(luò)或數(shù)據(jù)庫(kù)請(qǐng)求

flags為保留值,一般設(shè)為0.

/*!

* @function dispatch_get_global_queue

*

* @abstract

* Returns a well-known global concurrent queue of a given quality of service

* class.

*

* @discussion

* The well-known global concurrent queues may not be modified. Calls to

* dispatch_suspend(), dispatch_resume(), dispatch_set_context(), etc., will

* have no effect when used with queues returned by this function.

*

* @param identifier

* A quality of service class defined in qos_class_t or a priority defined in

* dispatch_queue_priority_t.

*

* It is recommended to use quality of service class values to identify the

* well-known global concurrent queues:

*? - QOS_CLASS_USER_INTERACTIVE

*? - QOS_CLASS_USER_INITIATED

*? - QOS_CLASS_DEFAULT

*? - QOS_CLASS_UTILITY

*? - QOS_CLASS_BACKGROUND

*

* The global concurrent queues may still be identified by their priority,

* which map to the following QOS classes:

*? - DISPATCH_QUEUE_PRIORITY_HIGH:? ? ? ? QOS_CLASS_USER_INITIATED

*? - DISPATCH_QUEUE_PRIORITY_DEFAULT:? ? ? QOS_CLASS_DEFAULT

*? - DISPATCH_QUEUE_PRIORITY_LOW:? ? ? ? ? QOS_CLASS_UTILITY

*? - DISPATCH_QUEUE_PRIORITY_BACKGROUND:? QOS_CLASS_BACKGROUND

*

* @param flags

* Reserved for future use. Passing any value other than zero may result in

* a NULL return value.

*

* @result

* Returns the requested global queue or NULL if the requested global queue

* does not exist.

*/

__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)

DISPATCH_EXPORT DISPATCH_CONST DISPATCH_WARN_RESULT DISPATCH_NOTHROW

dispatch_queue_t

dispatch_get_global_queue(long identifier, unsigned long flags);

另外跪者,調(diào)試和打日志時(shí),需要用到

dispatch_queue_t dispatch_get_current_queue(void);

函數(shù)得到當(dāng)前隊(duì)列逗概。

線程延時(shí)執(zhí)行:可以使用

void dispatch_after(dispatch_time_t when,

dispatch_queue_t queue,

dispatch_block_t block);

/*!

* @function dispatch_after

*

* @abstract

* Schedule a block for execution on a given queue at a specified time.

*

* @discussion

* Passing DISPATCH_TIME_NOW as the "when" parameter is supported, but not as

* optimal as calling dispatch_async() instead. Passing DISPATCH_TIME_FOREVER

* is undefined.

*

* @param when

* A temporal milestone returned by dispatch_time() or dispatch_walltime().

*

* @param queue

* A queue to which the given block will be submitted at the specified time.

* The result of passing NULL in this parameter is undefined.

*

* @param block

* The block of code to execute.

* The result of passing NULL in this parameter is undefined.

*/

#ifdef __BLOCKS__

__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)

DISPATCH_EXPORT DISPATCH_NONNULL2 DISPATCH_NONNULL3 DISPATCH_NOTHROW

void

dispatch_after(dispatch_time_t when,

dispatch_queue_t queue,

dispatch_block_t block);

#endif


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市铅搓,隨后出現(xiàn)的幾起案子星掰,更是在濱河造成了極大的恐慌氢烘,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,084評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件椎工,死亡現(xiàn)場(chǎng)離奇詭異晋渺,居然都是意外死亡木西,警方通過(guò)查閱死者的電腦和手機(jī)随静,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門恋捆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)重绷,“玉大人昭卓,你說(shuō)我怎么就攤上這事候醒。” “怎么了伙菊?”我有些...
    開(kāi)封第一講書人閱讀 163,450評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵镜硕,是天一觀的道長(zhǎng)谦疾。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么峰伙? 我笑而不...
    開(kāi)封第一講書人閱讀 58,322評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮栓袖,結(jié)果婚禮上裹刮,老公的妹妹穿的比我還像新娘捧弃。我一直安慰自己,他們只是感情好嘴办,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,370評(píng)論 6 390
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著眼五,像睡著了一般弹砚。 火紅的嫁衣襯著肌膚如雪桌吃。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,274評(píng)論 1 300
  • 那天,我揣著相機(jī)與錄音翎卓,去河邊找鬼摆寄。 笑死,一個(gè)胖子當(dāng)著我的面吹牛古戴,可吹牛的內(nèi)容都是我干的矩肩。 我是一名探鬼主播黍檩,決...
    沈念sama閱讀 40,126評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼刽酱,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼肛跌!你這毒婦竟也來(lái)了衍慎?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 38,980評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎砖织,沒(méi)想到半個(gè)月后侧纯,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體甲脏,經(jīng)...
    沈念sama閱讀 45,414評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡娜氏,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,599評(píng)論 3 334
  • 正文 我和宋清朗相戀三年贸弥,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了绵疲。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,773評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡帕胆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出驯用,到底是詐尸還是另有隱情蝴乔,我是刑警寧澤驮樊,帶...
    沈念sama閱讀 35,470評(píng)論 5 344
  • 正文 年R本政府宣布挖腰,位于F島的核電站练湿,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏肥哎。R本人自食惡果不足惜辽俗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,080評(píng)論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望篡诽。 院中可真熱鬧崖飘,春花似錦、人聲如沸杈女。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,713評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)碧信。三九已至,卻和暖如春砰碴,著一層夾襖步出監(jiān)牢的瞬間躏筏,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,852評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工呈枉, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留趁尼,地道東北人埃碱。 一個(gè)月前我還...
    沈念sama閱讀 47,865評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像酥泞,于是被迫代替她去往敵國(guó)和親砚殿。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,689評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • ?書法是我國(guó)古代人民智慧的結(jié)晶羡藐,自小看到會(huì)寫毛筆字的人對(duì)他們都特別的敬仰羨慕,這是一種特別神圣的藝術(shù)悯许,以至于小時(shí)候...
    形影々相依閱讀 684評(píng)論 0 1
  • 靜靜的第二堂主題美術(shù)課作品仆嗦,Merry Christmas!
    譚潭潭閱讀 145評(píng)論 0 0
  • 今天回學(xué)校了先壕,一回到教室就開(kāi)始我的手工DIY 瘩扼,今天做的是小貓咪,做好的第一個(gè)送給了我的大臉師傅垃僚,是不是很可愛(ài)呢 ...
    清風(fēng)微寒閱讀 175評(píng)論 1 2
  • 大學(xué)里我學(xué)的是生物集绰,而現(xiàn)在從事的工作是網(wǎng)絡(luò)推廣,目前正在學(xué)習(xí)SEO冈在,長(zhǎng)遠(yuǎn)目標(biāo)是精通推廣倒慧,包括線上及線下。當(dāng)初選專業(yè)...
    淘米日記本閱讀 509評(píng)論 0 1
  • 功夫和認(rèn)知 在傳統(tǒng)武術(shù)的領(lǐng)域包券,存在的各種對(duì)功夫的看法和認(rèn)知纫谅,爭(zhēng)論一直不停,但一直沒(méi)有一種判斷和停止?fàn)幷摰臋?quán)威的判定...
    a9ac3e50d244閱讀 456評(píng)論 0 0