Skip to content

๐Ÿƒ๐Ÿปโ€โ™‚๏ธ๐Ÿƒ๐Ÿปโ€โ™€๏ธ ๋Ÿฌ๋„ˆ์Šคํ•˜์ด iOS "์ง„์‹ฌ" ๋ ˆํฌ ๐Ÿƒ๐Ÿปโ€โ™‚๏ธ๐Ÿƒ๐Ÿปโ€โ™€๏ธ

Notifications You must be signed in to change notification settings

RunnersHi/RunnersHi_iOS

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

RUNNERS HI - iOS

๐Ÿƒ๐Ÿปโ€โ™‚๏ธ๐Ÿƒ๐Ÿปโ€โ™€๏ธ ๋Ÿฌ๋„ˆ์Šคํ•˜์ด iOS "์ง„์‹ฌ" ๋ ˆํฌ ๐Ÿƒ๐Ÿปโ€โ™‚๏ธ๐Ÿƒ๐Ÿปโ€โ™€๏ธ

  • ์ง„ํ–‰๊ธฐ๊ฐ„ : 2020๋…„ 6์›” 27์ผ ~ 7์›” 18์ผ 26th โ€˜SOPTโ€™ APPJAM
  • ์ฝ”๋“œ ๋ฆฌํŒฉํ† ๋ง ๊ธฐ๊ฐ„ : 2021๋…„ 3์›” 25์ผ ~

๋Ÿฌ๋‹์„ ๊ฒŒ์ž„์ฒ˜๋Ÿผ, ๋Ÿฌ๋„ˆ์Šคํ•˜์ด

์šฐ๋ฆฌ๋Š” 'ํ•จ๊ป˜' ๋›ธ ๋•Œ ๋” ๋งŽ์€ ์‹œ๋„ˆ์ง€๋ฅผ ๋งŒ๋“ค์–ด๋ƒ…๋‹ˆ๋‹ค. ์š”์ฆ˜ ์„ธ๋Œ€๋“ค์€ ๋Ÿฌ๋‹ ํฌ๋ฃจ์— ์†Œ์†๋˜์–ด ๋Ÿฌ๋‹์„ ์ฆ๊ธฐ๊ณค ํ•˜์ง€๋งŒ, Offline ๋Ÿฌ๋‹ํฌ๋ฃจ๋Š” ๊ณ ์ •๋œ ์‹œ๊ฐ„๊ณผ ์žฅ์†Œ๋ผ๋Š” ํ•œ๊ณ„์ ์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ๊ฐ™์ด ๋‹ฌ๋ฆฌ๊ณ  ์‹ถ์ง€๋งŒ, ๋‹ฌ๋ฆด ์ˆ˜ ์—†๋Š” ์ˆœ๊ฐ„๋“ค์ด ์กด์žฌํ•œ๋‹ค๋Š” ์ ์— ์ง‘์ค‘ํ•˜๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ์˜ ์„œ๋น„์Šค๋ฅผ ํ†ตํ•ด ์‹œ๊ณต๊ฐ„์˜ ์ œ์•ฝ์—†์ด ๋‹ค์–‘ํ•œ ์‚ฌ๋žŒ๋“ค๊ณผ ํ•จ๊ป˜ ๋‹ฌ๋ฆผ์œผ๋กœ์จ ๊ฑด๊ฐ•ํ•œ ๋ผ์ดํ”„ ์Šคํƒ€์ผ์„ ๋งŒ๋“ค์–ด๋‚˜๊ฐ€๊ธธ ๋ฐ”๋ž๋‹ˆ๋‹ค.

โญ๏ธ ๊ธฐ์กด ๋Ÿฌ๋‹ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ์˜ ํ™•์‹คํ•œ ์ฐจ๋ณ„ํ™” ์š”์†Œ๋ฅผ ์ ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

: ๊ธฐ์กด ๋Ÿฌ๋‹ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ์˜ ํ™•์‹คํ•œ ์ฐจ๋ณ„ํ™” ์š”์†Œ๋ฅผ ์ ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

โญ๏ธ ๋”ฐ๋กœ, ๋˜ ๊ฐ™์ด ํ•จ๊ป˜ ํ•˜๋Š” ๊ฐ€์น˜๋ฅผ ์ถ”๊ตฌํ•˜๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค.

: ์–ด๋–ค ๋‹จ์ฒด์— ์†Œ์†๋˜์ง€ ์•Š์•„๋„, ๊ตณ์ด ์นœ๊ตฌ์™€ ์•ฝ์†์„ ์žก๊ณ  ๋งŒ๋‚˜์ง€ ์•Š์•„๋„, ์‚ฌ์šฉ์ž๋Š” ์–ธ์ œ ์–ด๋””์„œ๋“  ๋‚˜์™€ ํ•จ๊ป˜ ๋›ธ ์ƒ๋Œ€๋ฅผ ์ฐพ์•„ ๊ฐ™์ด ๋Ÿฌ๋‹์„ ์ฆ๊ธธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

โญ๏ธ ํŠธ๋ Œ๋””ํ•œ ๋””์ž์ธ์  ์š”์†Œ๋ฅผ ํ†ตํ•ด ์‹œ๊ฐ์ ์ธ ์ฆ๊ฑฐ์›€์„ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

: ํŠน์ • ๋ชฉํ‘œ๋ฅผ ๋‹ฌ์„ฑํ•˜๋ฉด ๊ฐœ์„ฑ์žˆ๋Š” ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๋ฑƒ์ง€๋ฅผ ํš๋“ํ•  ์ˆ˜ ์žˆ์Œ๊ณผ ๋™์‹œ์— ๋‹ค์–‘ํ•œ ๋Ÿฌ๋„ˆ ๋žญํ‚น์„ ํ†ตํ•ด ์‚ฌ์šฉ์ž์˜ ์ฆ๊ฑฐ์›€์„ ๋„๋ชจํ•˜๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค. ๋˜, ๋ˆ„๊ตฌ๋‚˜ ์‚ฌ์šฉํ•˜๊ธฐ ์‰ฌ์šด UX ์š”์†Œ๋Š” ์ฆ๊ฑฐ์›€์„ ๋ฐฐ๋กœ ํ–ฅ์ƒ์‹œ์ผœ ์ค„๊ฑฐ์—์š”.

=> ๋ฐœํ‘œ์˜์ƒ ๋ณด๊ธฐ


A. Setting


B-1. ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ๋ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

Xcode swift Alamofire Socket.IO-Client-Swift XLPagerTabStrip NMapsMape


B-2. WORKFLOW

์ตœ์ข…๊ณผ์ œ  RUNNER'S HI WORKFLOW_page-0001


B-3. ๊ธฐ๋Šฅ ๋ช…์„ธ์„œ

์šฐ์„ ์ˆœ์œ„ ํ™”๋ฉด ์ด๋ฆ„ ๊ธฐ๋Šฅ ์ด๋ฆ„ ๊ตฌํ˜„ ๋‹ด๋‹น์ž
P1 ํšŒ์› ๊ฐ€์ž… ๊ธฐ๋ณธ ๋ฐ์ดํ„ฐ(๋‹‰๋„ค์ž„/์•„์ด๋””/๋น„๋ฐ€๋ฒˆํ˜ธ/์„ฑ๋ณ„/๋ ˆ๋ฒจ) ๋ฐ›๊ธฐ ๐Ÿ”ต ์ตœ์˜์žฌ
P2 ํŠœํ† ๋ฆฌ์–ผ ์Šคํ”Œ๋ž˜์‰ฌ ๐Ÿ”ต ๊น€๋ฏผํฌ
P1 ๋งค์นญํ™”๋ฉด ๋งค์นญ ๋ฐ์ดํ„ฐ(๋ชฉํ‘œ์‹œ๊ฐ„/์ƒ๋Œ€ ์„ฑ๋ณ„)๋ฐ›๊ธฐ ๐Ÿ”ต ๊น€๋ฏผํฌ
P1 ๋งค์นญํ™”๋ฉด ๋งค์นญ ๊ธฐ์ค€(๋ชฉํ‘œ์‹œ๊ฐ„/์„ฑ๋ณ„/๋ ˆ๋ฒจ)์— ๋”ฐ๋ผ ๋งค์นญ๋Ÿฌ๋„ˆ ์ฐพ๊ธฐ ๐Ÿ”ต ๊น€๋ฏผํฌ
P1 ๋งค์นญ์„ฑ๊ณตํ™”๋ฉด ์ƒ๋Œ€๋Ÿฌ๋„ˆ ํ”„๋กœํ•„, ๋ ˆ๋ฒจ, ์ „์  ๋ณด์—ฌ์ฃผ๊ธฐ ๐Ÿ”ต ๊น€๋ฏผํฌ
P1 ๋กœ๊ทธ์ธ ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ ๐Ÿ”ต ์ตœ์˜์žฌ
P1 ๋Ÿฌ๋‹์ค‘ํ™”๋ฉด ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋Ÿฌ๋‹๊ฑฐ๋ฆฌ, ํŽ˜์ด์Šค, ๋‚จ์€ ์‹œ๊ฐ„ ๋ณด์—ฌ์ฃผ๊ธฐ ๐Ÿ”ต ๊น€๋ฏผํฌ
P1 ๋Ÿฌ๋‹์ค‘ํ™”๋ฉด ์นด์šดํŠธ๋‹ค์šด ๐Ÿ”ต ๊น€๋ฏผํฌ
P1 ๋Ÿฌ๋‹์ค‘ํ™”๋ฉด ํœด๋Œ€ํฐ ์‚ฌ์šฉ์ž ๋™์ž‘ ๋ฐ ํ”ผํŠธ๋‹ˆ์Šค ํ™œ๋™ ์ ‘๊ทผ ๐Ÿ”ต ๊น€๋ฏผํฌ
P2 ๋Ÿฌ๋‹์ค‘ํ™”๋ฉด ํ˜„์žฌ ์œ„์น˜ ํ‘œ์‹œ ๐Ÿ”ต ๊น€๋ฏผํฌ
P2 ๋Ÿฌ๋‹๋žญํ‚นํ™”๋ฉด 1) ์ด๋™๊ฑฐ๋ฆฌ ๋†’์€์ˆœ 2)์Šน์ด ๋งŽ์€ ์ˆœ 3)ํŒจ๊ฐ€ ๋งŽ์€ ์ˆœ ์‚ฌ์šฉ์ž ๋žญํ‚น ๐Ÿ”ต ์ตœ์˜์žฌ
P2 ๋Ÿฌ๋‹๊ธฐ๋กํ™”๋ฉด ๋‚˜์˜ ๋Ÿฌ๋‹๋ฐ์ดํ„ฐ ๋ชจ์•„์„œ ๋ณด์—ฌ์ฃผ๊ธฐ ๊ธฐ๋Šฅ ๐Ÿ”ต ์ตœ์˜์žฌ
P2 ๋Ÿฌ๋‹๊ธฐ๋กํ™”๋ฉด ๋Ÿฌ๋‹ ๋ฑƒ์ง€ ๋ชจ์•„์„œ ๋ณด์—ฌ์ฃผ๊ธฐ ๊ธฐ๋Šฅ ๐Ÿ”ต ์ตœ์˜์žฌ
P2 ๋Ÿฌ๋‹๊ฒฐ๊ณผํ™”๋ฉด ๋‘ ๋Ÿฌ๋„ˆ์˜ ์ด๋™๊ฑฐ๋ฆฌ ๋น„๊ต ๊ธฐ๋Šฅ ๐Ÿ”ต ๊น€๋ฏผํฌ
P1 ๋Ÿฌ๋‹๊ฒฐ๊ณผํ™”๋ฉด ๋‚˜์˜ ๊ธฐ๋ก/์ƒ๋Œ€๋Ÿฌ๋„ˆ ๊ธฐ๋ก ๋ชจ์•„์„œ ๋ณด์—ฌ์ฃผ๊ธฐ ๊ธฐ๋Šฅ ๐Ÿ”ต ๊น€๋ฏผํฌ
P2 ๋งˆ์ดํŽ˜์ด์ง€ ๋‚˜์˜ ํ”„๋กœํ•„ ์ด๋ฏธ์ง€/๋‹‰๋„ค์ž„/์ŠนํŒจ/๋ ˆ๋ฒจ/๋ฑƒ์ง€ ํ‘œ์‹œ ๐Ÿ”ต ์ตœ์˜์žฌ

C-1. ๊ฐœ๋ฐœ ์„ค๋ช…

Tab Bar

: Tab Bar์„ ์ด์šฉํ•ด ๊ฐ ์Šคํ† ๋ฆฌ๋ณด๋“œ๋ฅผ ์ด์–ด์ฃผ๋ฉฐ ์ด๋™ ๊ฐ€๋Šฅ

ํšŒ์›๊ฐ€์ž…, ๋กœ๊ทธ์ธ ํ™”๋ฉด

๐Ÿฅณ ๋กœ๊ทธ์ธ, ํšŒ์›๊ฐ€์ž… ํ™”๋ฉด. ์ •๊ทœํ‘œํ˜„์‹ ๊ฒ€์‚ฌ์™€ ์•„์ด๋””, ๋‹‰๋„ค์ž„ ์ค‘๋ณต ๊ฒ€์‚ฌ ์ž๋™๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ์„ ํฌํ•จํ•œ๋‹ค.

๋กœ๊ทธ์ธ ํšŒ์›๊ฐ€์ž…_๊ธฐ๋ณธ ํšŒ์›๊ฐ€์ž…_์ค‘๊ฐ„ ํšŒ์›๊ฐ€์ž…_์™„๋ฃŒ

Running Tab(ํ™ˆ ํ™”๋ฉด)

๐Ÿฅณ Main ํ™”๋ฉด. ์ผ๋Ÿฌ์ŠคํŠธ๋กค ํฌํ•จํ•˜๋ฉฐ, RUN NOW ๋ฒ„ํŠผ ํด๋ฆญ์‹œ ์ฃผ์š” ๊ธฐ๋Šฅ์€ ๋งค์นญ ์„œ๋น„์Šค๊ฐ€ ์‹œ์ž‘๋œ๋‹ค. ์›ํ•˜๋Š” ๋งค์นญ ๋Ÿฌ๋„ˆ์˜ ์กฐ๊ฑด์„ ์„ค์ •ํ•˜๊ณ  ๋งค์นญ์ด ๋˜๋ฉด ์ƒ๋Œ€๋ฐฉ ํ”„๋กœํ•„์„ ํ™•์ธํ•œ ํ›„, ๋Ÿฌ๋‹์ด ์‹œ์ž‘๋œ๋‹ค.
๐Ÿค“ ์ถ”ํ›„ develop์œผ๋กœ ํ˜ผ์ž ๋‹ฌ๋ฆฌ๊ธฐ๋ฅผ ํ†ตํ•ด ๋งค์นญ์ด ์•ˆ๋˜๋Š” ์‚ฌ๋žŒ๋“ค ํ˜น์€ ํ˜ผ์ž ๋Ÿฌ๋‹์„ ์ธก์ •ํ•ด๋ณด๊ณ  ์‹ถ์€ ์‚ฌ๋žŒ๋“ค์„ ์œ„ํ•œ ์„œ๋น„์Šค๋ฅผ ์ œ๊ณตํ•˜๊ณ ์ž ํ•œ๋‹ค.
RunningTab RunningTab-๋งค์นญ ์Šคํฌ๋ฆฐ์ƒท 2020-07-17 ์˜คํ›„ 11 06 42
์Šคํฌ๋ฆฐ์ƒท 2020-07-17 ์˜คํ›„ 11 06 46 ์Šคํฌ๋ฆฐ์ƒท 2020-07-17 ์˜คํ›„ 11 06 49

๐Ÿฅณ ๋งค์นญ์ด ๋˜๋ฉด ์ƒ๋Œ€๋ฐฉ ํ”„๋กœํ•„์„ ํ™•์ธํ•œ ํ›„, ๋Ÿฌ๋‹์ด ์‹œ์ž‘๋œ๋‹ค. ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ž์‹ ์˜ ์†๋„(km), ํŽ˜์ด์Šค(pace), ๋‚จ์€ ์‹œ๊ฐ„์ด ํ‘œ์‹œ๋˜๊ณ  ํ˜„์žฌ ์ž์‹ ์ด ๋›ฐ๊ณ ์žˆ๋Š” ์œ„์น˜๊ฐ€ ์ง€๋„(๋„ค์ด๋ฒ„)๋ฅผ ํ†ตํ•ด ํ‘œ์‹œ๋œ๋‹ค.
๐Ÿค“ ํ˜„์žฌ๋Š” ์ž์‹ ์ด ์žˆ๋Š” ์œ„์น˜๋งŒ ํ‘œ์‹œ๋˜์ง€๋งŒ, ์ถ”ํ›„ ์ž์‹ ์ด ๋Ÿฌ๋‹ํ•œ ๊ฒฝ๋กœ๊ฐ€ ๋œจ๊ฒŒ ํ•  ์ƒ๊ฐ์ด๋‹ค. (ํ˜„์žฌ ๋„ค์ด๋ฒ„์ธก์—์„œ points ์†์„ฑ์„ ๋ง‰์•„๋‘”๊ฒƒ์œผ๋กœ ๋ณด์—ฌ ๊ตฌํ˜„ํ•˜์ง€ ๋ชปํ•œ ์•„์‰ฌ์›€์ด ์žˆ๋‹ค.)๋„ค์ด๋ฒ„ ์ง€๋„ iOS SDK

๋งค์นญ๋œ๋Ÿฌ๋„ˆํ”„๋กœํ•„ ๋งค์นญ_๋Ÿฌ๋‹์ค‘ ์‹ค์‹œ๊ฐ„๋Ÿฌ๋‹์ค‘
์กŒ๋‹ค์ด๊ฒผ๋‹ค

Record Tab

: ์ž์‹ ์ด ์ง€๊ธˆ๊นŒ์ง€ ์Œ“์•„์˜จ ๋Ÿฌ๋‹ ๊ธฐ๋ก๊ณผ ๋ชจ์•„์˜จ ๋Ÿฌ๋‹๋ฑƒ์ง€๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

RecordTab RecordTab-๋ฑƒ์ง€

Ranking Tab

: ํ˜„์žฌ ์ด ์–ดํ”Œ์—์„œ '์ด๋‹ฌ์˜ ๋Ÿฌ๋„ˆ', '๋ช…์˜ˆ์˜ ์ „๋‹น', '์กŒ.์ž˜.์‹ธ' ๋กœ ๋‚˜๋ˆ ์ง„ 3๊ฐœ์˜ ๋žญํ‚น ์ˆœ์œ„๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

RankingTab

MyPage Tab

: ์ž์‹ ์˜ ๊ธฐ๋ณธ ์ •๋ณด(ํ”„๋กœํ•„ ์‚ฌ์ง„, ๋‹‰๋„ค์ž„, ๋ ˆ๋ฒจ, ์ „์ )์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๊ณ  ๋ชจ์•„๋‘” ๋ฑƒ์ง€๋ฅผ ๊ฐ„๋žตํžˆ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

MypageTab


C-2. ๐ŸŒŸ์ƒˆ๋กœ ์•Œ๊ฒŒ ๋œ ๊ธฐ๋Šฅ๐ŸŒŸ

1) Healthkit

๐Ÿ’ช๐Ÿป์šด๋™ ์–ดํ”Œ์˜ ๊ธฐ๋ณธ! '๊ฑด๊ฐ•' ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ์—ฐ๋™ํ•ด์„œ ๊ฐ’ ๊ฐ€์ ธ์˜ค๊ธฐ ! ๋„์ „ !๐Ÿ’ช๐Ÿป

  1. ๋จผ์ € ๊ฑด๊ฐ• ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์—ฐ๋™ํ•˜๋ ค๋ฉด Apple Developer Program Membership ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค (์œ ๋ฃŒ)
  2. Capability์—์„œ Healthkit๋ฅผ ์ถ”๊ฐ€ํ•ด ํ™œ์„ฑํ™” ์‹œ์ผœ์ค๋‹ˆ๋‹ค.

Healthkit ์—ฐ๋™

  1. info.plist ํŒŒ์ผ์—์„œ Information Property List Key Reference๋ฅผ ์ถ”๊ฐ€ํ•ด์ค๋‹ˆ๋‹ค.

์Šคํฌ๋ฆฐ์ƒท 2020-07-08 ์˜คํ›„ 8 40 09

  1. HealthKit ์•ก์„ธ์Šค๋ฅผ ํ—ˆ์šฉํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์งœ์•ผํ•ฉ๋‹ˆ๋‹ค.
  • ์ด ๊ธฐ๊ธฐ์—์„œ HealthKit๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ.
guard HKHealthStore.isHealthDataAvailable() else {
    completion(false, HealthkitSetupError.notAvailableOnDevice)
    return
  }
  • HealthKit๊ณผ ์ƒํ˜ธ ์ž‘์šฉํ•  ๋ฐ์ดํ„ฐ ์œ ํ˜• ์ค€๋น„ํ•˜๊ธฐ.
    guard   let walkAddRun = HKObjectType.quantityType(forIdentifier: .distanceWalkingRunning),
    //๊ฑท๊ธฐ+๋‹ฌ๋ฆฌ๊ธฐ ๊ฑฐ๋ฆฌ(walkAddRun)
          let step = HKObjectType.quantityType(forIdentifier: .stepCount),
          // ์‹ฌ๋ฐ•์ˆ˜
          let activeEnergy = HKObjectType.quantityType(forIdentifier: .activeEnergyBurned)
          //ํ™œ๋™์—๋„ˆ์ง€
          else {
          let activeEnergy = HKObjectType.quantityType(forIdentifier: .activeEnergyBurned) else {
          completion(false, HealthkitSetupError.dataTypeNotAvailable)
          return
  }

(๋ฐ์ดํ„ฐ ์œ ํ˜•์€ https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier ์—์„œ ์ฐธ๊ณ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.)

  • HealthKit์ด ์ฝ๊ณ  ์“ธ ์œ ํ˜• ๋ชฉ๋ก ์ž‘์„ฑํ•˜๊ธฐ
let healthKitTypesToWrite: Set<HKSampleType> = [walkAddRun,
                                                 activeEnergy,
                                                 step,
                                                 HKObjectType.workoutType()
                                                 ]
 
 let healthKitTypesToRead: Set<HKObjectType> = [walkAddRun,
                                                activeEnergy,
                                                HKObjectType.workoutType()
                                                 ]

healthKitTypesToWrite๋Š” ์–ดํ”Œ์ด ๋‹ค์Œ ๋ฐ์ดํ„ฐ๋ฅผ ์“ฐ๊ธฐ ํ—ˆ์šฉํ•˜๋Š” ๋ชฉ๋ก, healthKitTypesToRead๋Š” ์–ดํ”Œ์ด ๋‹ค์Œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ธฐ ํ—ˆ์šฉํ•˜๋Š” ๋ชฉ๋ก์ž…๋‹ˆ๋‹ค.

  • ์š”์ฒญ ์Šน์ธ ๋ฐ›๊ธฐ
HKHealthStore().requestAuthorization(toShare: healthKitTypesToWrite,
                                      read: healthKitTypesToRead) { (success, error) in
   completion(success, error)
 }

2) ์‹ค์‹œ๊ฐ„ ํ†ต์‹  ์ธ์ƒ ์ฒซ ์†Œ์ผ“ ํ†ต์‹  ๋„์ „ !๐Ÿ’ช๐Ÿป

-> ์„œ๋ฒ„ ์ž๋ฃŒ ํ™•์ธํ•˜๊ธฐ

import SocketIO
   static let shared = SocketIOManager()
   var manager = SocketManager(socketURL: URL(string: "์†Œ์ผ“์ฃผ์†Œ")!, config: [.log(true), .compress])
   var socket: SocketIOClient!
   
   FindRunnerVC.socket = FindRunnerVC.self.manager.socket(forNamespace: "/matching")

: ์–ดํ”Œ์—์„œ ์†Œ์ผ“ ํ†ต์‹ ์„ ์“ฐ๋Š” ๋ฒ”์œ„๋Š” ๋งค์นญ ๋Ÿฌ๋„ˆ๋Š” ์ฐพ์„ ๋•Œ๋ถ€ํ„ฐ ๊ฒŒ์ž„์ด ๋๋‚˜๊ณ  ๊ฒฐ๊ณผ ๋น„๊ต ์ „๊นŒ์ง€ ์†Œ์ผ“ ํ†ต์‹ ์„ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.
ํ•œ ๋ทฐ์—์„œ๋งŒ ์†Œ์ผ“ ํ†ต์‹ ์ด ์“ฐ์ด๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์†Œ์ผ“์ด ์—ฐ๊ฒฐ๋ผ์„œ ์—ฌ๋Ÿฌ ๋ทฐ๋ฅผ ํ†ต๊ณผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‹ฑ๊ธ€ํ†ค์„ ์‚ฌ์šฉํ•ด์„œ ํ†ต์‹ ์„ ์ด์–ด๊ฐ”์Šต๋‹ˆ๋‹ค.

   FindRunnerVC.socket.on("start", callback: { (data, ack) in
     FindRunnerVC.self.socket.emit("joinRoom",myToken,myGoal,myWantGender,self.leftTime)
        })

: ์„œ๋ฒ„๋Š” ์‹œ์ž‘ํ•ด๋„ ์ข‹๋‹ค๋Š” ์‘๋‹ต -> ํด๋ผ๋Š” ๋‚ด ์ •๋ณด์™€ ๋‚ด๊ฐ€ ์›ํ•˜๋Š” ์ƒ๋Œ€์˜ ์กฐ๊ฑด์„ ๋ณด๋‚ด์ค๋‹ˆ๋‹ค.

        FindRunnerVC.socket.on("roomCreated", callback: { (data, ack) in
            FindRunnerVC.self.socket.emit("startCount",data[0] as! SocketData)
        })

: ๋‚ด๊ฐ€ ์›ํ•˜๋Š” ์กฐ๊ฑด์˜ ์ƒ๋Œ€๋ฅผ ์ฐพ์ง€ ๋ชปํ•œ๋‹ค๋ฉด ์„œ๋ฒ„๋Š” ์ƒˆ๋กœ์šด ๋ฐ›์„ ๋งŒ๋“ค์–ด์„œ ๋‚˜๋ฅผ ๋„ฃ์–ด์ฃผ๊ณ  -> ํด๋ผ๋Š” ์‹œ๊ฐ„ ์นด์šดํŠธ๋ฅผ ํ•˜๋ผ๊ณ  ์•Œ๋ ค์ค๋‹ˆ๋‹ค. roomCreated ๋•Œ ๋ฐ›๋Š” ์ •๋ณด์ธ data[0]์€ ๋‚ด๊ฐ€ ์†ํ•ด์žˆ๋Š” ๋ฐฉ์˜ ๋ฒˆํ˜ธ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

        FindRunnerVC.socket.on("matched", callback: { (data, ack) in
            FindRunnerVC.self.socket.emit("endCount",data[0] as! SocketData)
        })

: ๋Œ€๊ธฐ์ค‘์— ์ƒ๋Œ€๋ฅผ ์ฐพ์•˜์„๋•Œ๋Š” ์„œ๋ฒ„๋Š” matched์™€ data[0]์œผ๋กœ ๋‚ด๊ฐ€ ์†ํ•œ ๋ฐฉ ์ด๋ฆ„์„ ๋ณด๋‚ด์ฃผ๊ณ , ํด๋ผ์—์„œ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์†ํ•œ ๋ฐฉ์˜ ์ด๋ฆ„๊ณผ endCount๋ฅผ ๋ณด๋‚ด์ค๋‹ˆ๋‹ค.

        FindRunnerVC.socket.emit("compareResult",UserDefaults.standard.object(forKey: "opponentRoom") as? String ?? " ",UserDefaults.standard.object(forKey: "opponetDistance") as? Int ?? 2,UserDefaults.standard.object(forKey: "myGoalTime") as? Int ?? 0,array2,UserDefaults.standard.object(forKey: "createdTime") as? String ?? " ",UserDefaults.standard.object(forKey: "endTime") as? String ?? " ")

: ๋Ÿฌ๋‹ ๊ฒŒ์ž„์ด ๋๋‚˜๋ฉด ๋‚˜์˜ ๋ฐฉ ๋ฒˆํ˜ธ, ๋‹ฌ๋ฆฐ ๊ฑฐ๋ฆฌ, ๋‹ฌ๋ฆฐ ์‹œ๊ฐ„, ๋ฐฉ ๋ฒˆํ˜ธ, ์ง€๋„ ์œ„์น˜, ์‹œ์ž‘ํ•œ ์‹œ๊ฐ„, ๋๋‚œ ์‹œ๊ฐ„์„ ํ•จ๊ป˜ ๋ณด๋‚ด์ค๋‹ˆ๋‹ค.

3) ํšŒ์›๊ฐ€์ž… ๊ธฐ๋Šฅ

  • ์ •๊ทœํ‘œํ˜„์‹๊ณผ ์‹ค์‹œ๊ฐ„ ์ž…๋ ฅ ์ฒดํฌ
   private func loginCheck() {
        idTextField.addTarget(self, action: #selector(idTextChecked(_:)), for: .editingChanged)
        nickTextField.addTarget(self, action: #selector(nickTextChecked(_:)), for: .editingChanged)
        pwTextField.addTarget(self, action: #selector(pwTextChecked(_:)), for: .editingChanged)
        pwReTextField.addTarget(self, action: #selector(pwReTextChecked(_:)), for: .editingChanged)
    }

editingChanged๋ฅผ ํ™œ์šฉํ•œ ํ•จ์ˆ˜๋ฅผ ์„ ์–ธํ•ด์ฃผ์–ด ์‹ค์‹œ๊ฐ„์œผ๋กœ ์กฐ๊ฑด์— ๋งž๋Š” ์ž…๋ ฅ์ด ๋“ค์–ด์˜ค๋Š”์ง€ ์ฒดํฌํ•˜๊ณ , ๊ทธ์— ๋”ฐ๋ฅธ ํ…์ŠคํŠธ๋ฅผ ๋„์šฐ๊ฑฐ๋‚˜, ์กฐ๊ฑด์— ๋งž์•„์•ผ ๋‹ค๋ฅธ ๋™์ž‘๋“ค์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ–ˆ๋‹ค.

    func isValidNick(nick: String?) -> Bool {
        guard nick != nil else { return false }
        let regEx = "[ใ„ฑ-ใ…Žใ…-ใ…ฃ๊ฐ€-ํžฃA-Za-z0-9]{2,6}"
        let pred = NSPredicate(format:"SELF MATCHES %@", regEx)
        return pred.evaluate(with: nick)
    }

๋‹‰๋„ค์ž„ ์ •๊ทœํ‘œํ˜„ ์กฐ๊ฑด

ํ…์ŠคํŠธ ํ•„๋“œ๊ฐ€ ์กฐ๊ฑด์— ๋งž์ง€ ์•Š๋Š”๋‹ค๋ฉด, ์˜ค๋ฅ˜ ๋ฉ”์„ธ์ง€์™€ ํ•จ๊ฒŒ ํ…์ŠคํŠธ ํ•„๋“œ์˜ ๋””์ž์ธ์„ ๋ณ€๊ฒฝํ•ด์ฃผ๊ณ  ๋‹ค์Œ์œผ๋กœ ๋„˜์–ด๊ฐˆ ์ˆ˜ ์žˆ๋Š” ๋ฒ„ํŠผ์„ ๋น„ํ™œ์„ฑํ™” ์‹œํ‚ค๋Š” ๋“ฑ์˜ ๊ตฌํ˜„์„ ํ–ˆ๋‹ค. ์ •๊ทœํ‘œํ˜„์‹ ์ž์ฒด๋ณด๋‹ค๋Š” ์‹ค์‹œ๊ฐ„์œผ๋กœ ์‚ฌ์šฉ์ž์˜ ์ž…๋ ฅ์„ ํ™•์ธํ•˜์—ฌ ์กฐ๊ฑด์„ ๊ฒ€์‚ฌํ•ด์ฃผ๋Š” ๋ถ€๋ถ„์ด ์–ด๋ ค์› ๋Š”๋ฐ, ์šฐ๋ฆฌ ํŒ€์˜ ๊ฒฝ์šฐ์—๋Š” ํšŒ์›๊ฐ€์ž…์‹œ์— ์ฒดํฌํ•ด์•ผํ•˜๋Š” ์กฐ๊ฑด์ด ๋‹ค์–‘ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ทฐ๋ฅผ ์งœ๋Š” ๊ณผ์ •์ด ๊นŒ๋‹ค๋กญ๊ณ  ์‹œ๊ฐ„์ด ์˜ค๋ž˜๊ฑธ๋ ธ๋‹ค.

  • ์ปฌ๋ ‰์…˜ ๋ทฐ์™€ IsSelected๋ฅผ ํ™œ์šฉํ•œ ์„ ํƒ์ง€ ๊ตฌํ˜„

      override var isSelected: Bool {
          willSet {
              self.genderActionLabel.backgroundColor = newValue ? UIColor.lightishBlue : UIColor.brownishGrey
              print(genderActionLabel.text ?? nil!)           

ํšŒ์›๊ฐ€์ž…์‹œ์— ์‚ฌ์šฉ์ž์˜ ์ถ”๊ฐ€ ์ •๋ณด๋ฅผ ์ž…๋ ฅํ•ด์•ผํ•˜๋Š” ๋ถ€๋ถ„์„ ์ฒ˜์Œ์—๋Š” ๋‹จ์ˆœํ•˜๊ฒŒ ๋ฒ„ํŠผ์œผ๋กœ ๊ตฌํ˜„ํ•˜๋ ค๊ณ  ํ•˜์˜€๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์‚ฌ์šฉ์ž๊ฐ€ ํ•˜๋‚˜์˜ ์„ ํƒ์ง€๋งŒ์„ ์„ ํƒํ•ด์•ผํ•˜๊ณ , ๊ทธ ๊ฐ’๋งŒ์„ ์„œ๋ฒ„์— ์ „๋‹ฌํ•ด์•ผํ•˜๋Š” ์กฐ๊ฑด ํƒ“์— ์ผ๋ฐ˜ ๋ฒ„ํŠผ์œผ๋กœ๋Š” ๊ธฐํš์„ ๊ตฌํ˜„ํ•  ์ˆ˜๊ฐ€ ์—†์—ˆ๋‹ค. ๊ทธ๋ ‡๊ธฐ์— ์ปฌ๋ ‰์…˜ ๋ทฐ์—์„œ IsSelected๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์‚ฌ์šฉ์ž๊ฐ€ ํ•˜๋‚˜๋งŒ์˜ ์„ ํƒ์ง€๋ฅผ ๊ณ ๋ฅผ ์ˆ˜ ์žˆ๊ฒŒ ๊ตฌํ˜„ํ•˜์˜€๋‹ค. ์•ˆ๋“œ๋กœ์ด๋“œ์—์„œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ๊ณต๋˜๋Š” ๊ธฐ๋Šฅ์ด์ง€๋งŒ, iOS์—์„œ๋Š” ์ผ์ผ์ด ๊ตฌํ˜„ํ•ด์ฃผ์–ด์•ผํ•˜๋Š” ๊ธฐ๋Šฅ์ด์—ˆ๋‹ค. ์ „ํ˜€ ์•Œ์ง€ ๋ชปํ•˜๋˜ ๊ธฐ๋Šฅ์ด์—ˆ๊ธฐ์— ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์˜ ๋„์›€์„ ๋ฐ›์•˜๊ณ , ๊ตฌ๊ธ€๋ง๊ณผ ์ž‘์—…์„ ํ•˜๋Š”๋ฐ์— ๋งŽ์€ ์‹œ๊ฐ„์ด ๋“ค์—ˆ๋‹ค.

4) CoreMotion

  • CoreMotion์€ ํœด๋Œ€ํฐ์˜ ์„ผ์„œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค. ์›๋ž˜ Healthkit๋ฅผ ์‚ฌ์šฉํ–ˆ์ง€๋งŒ, Healthkit๋Š” ๋งŽ์€ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•ด์ฃผ์ง€๋งŒ ์—…๋ฐ์ดํŠธ๊ฐ€ ์‹ค์‹œ๊ฐ„(๋ช‡ ์ดˆ ๋‹จ์œ„)๋กœ ๋˜์ง€์•Š๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ด์„œ CoreMotion์œผ๋กœ ์ˆ˜์ •ํ•˜์˜€๋‹ค.coremotion์„ ์ด์šฉํ•ด์„œ ์‹ค์‹œ๊ฐ„ ๊ฑฐ๋ฆฌ๋ฅผ ๋ฐ›์•„์™”๋‹ค. ๋ฌผ๋ก  ์—ฌ๊ธฐ์„œ๋„ ํŽ˜์ด์Šค๋ฅผ ๊ณ„์‚ฐํ•ด์ฃผ์ง€๋งŒ ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ๋‹จ์œ„์™€๋Š” ๋‹ฌ๋ž๊ธฐ๋•Œ๋ฌธ์— ํŽ˜์ด์Šค๋Š” ์ง์ ‘ ๊ณ„์‚ฐํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ–ˆ๋‹ค.
    CoreMotion
pedometer = CMPedometer()

: CMPedometer๋Š” ์‹ค์‹œ๊ฐ„ ๊ฑท๊ธฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•œ ๊ฐœ์ฒด์ด๋‹ค. ์ฆ‰ ๋งŒ๋ณด๊ธฐ์˜ ์—ญํ• ์„ ํ•œ๋‹ค. ๋งŒ๋ณด๊ธฐ๋ฅผ ํ†ตํ•ด ๊ฑธ์Œ ์ˆ˜ ๋ฐ ์ด๋™ ํ•œ ๊ฑฐ๋ฆฌ์™€ ์ƒ์Šน ๋˜๋Š” ํ•˜๊ฐ• ํ•œ ์ธต ์ˆ˜์— ๋Œ€ํ•œ ๊ธฐํƒ€ ์ •๋ณด๋ฅผ ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

        pedometer.startUpdates(from: Date(), withHandler: { 
          (pedometerData, error) in
            if let pedData = pedometerData{
                self.numberOfSteps = Int(pedData.numberOfSteps)
                if let distance = pedData.distance{
                    self.distance = Double(distance)
                }
                if let averageActivePace = pedData.averageActivePace {
                    self.averagePace = Double(averageActivePace)
                }
                if let currentPace = pedData.currentPace {
                    self.pace = Double(currentPace)
                }
            } else {
                self.numberOfSteps = nil
            }
        })

: startUpdates ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ๋ณดํ–‰์ž ๊ด€๋ จ ๋ฐ์ดํ„ฐ๋ฅผ ์•ฑ์— ๋Œ๊ณ ์˜จ๋‹ค. distance๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ๊ฑท๊ฑฐ๋‚˜ ๋›ฐ๋Š” ๋™์•ˆ ์ด๋™ํ•œ ๊ฑฐ๋ฆฌ๋ฅผ ๊ฐ€์ ธ์™€์ค€๋‹ค. averageActivePace๋Š” ๋ฏธํ„ฐ๋‹น ์ดˆ ๋‹จ์œ„๋กœ ํ™˜์‚ฐํ•œ ํ‰๊ท  ํŽ˜์ด์Šค์ด๋‹ค. currentPace๋Š” ๋ฏธํ„ฐ๋‹น ์ดˆ ๋‹จ์œ„๋กœ ์ธก์ •ํ•œ ํ˜„์žฌ ์†๋„์ด๋‹ค. ์ด๋ ‡๊ฒŒ CoreData์—์„œ๋Š” ๋‹ฌ๋ฆฌ๊ธฐ์—์„œ ํ•„์š”ํ•œ ๋งŽ์€ ์ •๋ณด๋“ค์„ ์ œ๊ณตํ•œ๋‹ค.


D. ํŒ€์› ์—ญํ•  ๋ฐ ์†Œ๊ฐœ

  • ๊น€๋ฏผํฌ Repo : ๋Ÿฌ๋„ˆ์Šคํ•˜์ด iOS ๋ฆฌ๋“œ๊ฐœ๋ฐœ์ž, MainTab ๊ตฌํ˜„ ๋ฐ ์†Œ์ผ“ ํ†ต์‹  ๋‹ด๋‹น
  • ์ตœ์˜์žฌ Repo : ๋Ÿฌ๋„ˆ์Šคํ•˜์ด iOS ์„œ๋ธŒ๊ฐœ๋ฐœ์ž, RankTab / RecordTab / MyPabeTab / SignTab ๋‹ด๋‹น ๋ฐ http ํ†ต์‹  ๋‹ด๋‹น

F. ๊ฒฐ๊ณผ / ์„ฑ๊ณผ

: IT ์ฐฝ์—… ๋™์•„๋ฆฌ 26th โ€˜SOPTโ€™ APPJAM ๋Œ€์ƒ ์ˆ˜์ƒ, ํ˜„์žฌ ์•ฑ์Šคํ† ์–ด ์ถœ์‹œ ์ค€๋น„ ์ค‘.

About

๐Ÿƒ๐Ÿปโ€โ™‚๏ธ๐Ÿƒ๐Ÿปโ€โ™€๏ธ ๋Ÿฌ๋„ˆ์Šคํ•˜์ด iOS "์ง„์‹ฌ" ๋ ˆํฌ ๐Ÿƒ๐Ÿปโ€โ™‚๏ธ๐Ÿƒ๐Ÿปโ€โ™€๏ธ

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •