Obj-C, AutoLayout, ReactNative, Flutter, SwiftUI, 개발생산성 등등

최근에 다시 Swift/SwiftUI를 스터디하며 그동안 iOS 개발을 하며 느꼈던 UI 개발에 대한 개인적인 생각을 정리해봤습니다. 시작과 끝에 대략 10년정도의 시간차이가 있습니다.

Obj-C, InterfaceBuilder 재미있었음

Objective-C를 접한건 2009년 4월. 델파이(Pascal)에 익숙해져 있던 나에겐 NS…로 시작하는 긴 함수명을 가진 프레임워크가 의외로 익숙했고 그해에 여러개의 앱을 스토어에 업로드해서 통산 100만 다운로드는 넘기는 경험을 해보기도 했다. 무료앱이라 그다지 수익을 내지는 못했지만… ^^;

Interface Builder는 델파이의 화면디자이너와 유사했고 시간이 지나며 StoryBoard로 화면이 통합되는 과정에 사이즈 때문에 느려지는 문제들이 있었지만 최소한의 일관성은 유지 했다는 측면에서 나쁘지 않았다는 생각

Obj-C, AotoLayout 재미없었음

iOS앱 개발이 재미가 없어지기 시작한 시점은 아마도 Xcode에 AutoLayout이 적용되기 시작한 시점이었던것 같은데 기껏 화면을 디자인해 놓으면 수정사항이 발생할때마다 Layout이 깨지고 화면전체의 레이아웃을 다시 잡아야하는 불편함을 감수해야 하는게 너무 싫었음. 시간이 지나면서 언어가 Obj-C에서 Swift로 바꿔었지만 UI를 만드는 과정에 너무 번거로운 상황이 반복되면서 점점 흥미를 잃기 시작

ReactNative, CSS 흥미로움

독립개발자에서 취직을 하면서 iOS와 Android를 동시에 지원해야 하는 일이 생기면서 멀티 플랫폼에 대한 고민을 하게 되었는데 적은 리소스로 목적을 달성해야하는 스타트업 비즈니의 환경에 적합한 솔루션을 찾은것이 ReactNative. (이하 RN)

RN은 웹개발 기술을 기반으로 하고 있는데 HTML, CSS를 이용한 화면 구성이 위에 언급한 AutoLayout과 대비되면서 Xcode에도 이런 방법이 도입되어야 하지 않을까 하는 생각을 했었던 기억.

Flutter, Widget 괜찮긴한데…

멀티플랫폼은 한번 발을 들이면 쉽게 빠져 나갈수 없는데, 아이폰과 안드로이드를 한번에 빌드할 수 있다는데 누가 관심을 갖지 않겠는가? 그런면에서 Flutter는 구글의 후광을 입고 가장 빠르게 성장하고 있는 모바일 개발 플랫폼. 성능도 꽤 괜찮다.

위젯기반의 UI 레이아웃은 좀 심하다 싶게 캐스케이드 되는것을 제외하면 화면 변경이 용이하고 코드와 레이아웃간의 연결성도 나쁘지 않은편. 이것은 위에 언급한 RN도 거의 동일한 개발 편의성을 가지고 있지만 Flutter가 Android Studio 지원등에서 장점이 있고, 패키지 관리등에서 RN보다 좋은점이 많이 있음.

1년이 넘게 Flutter를 쓰면서 문제점이 나타나기 시작한 부분은 UI는 아니고 패키지 관리 부분이었는데 과도하게 외부 패키지를 사용하면 각 버전들의 의존성이 달라서 업데이트에 애를먹는 상황이 발생하게 되는데 이부분 좀 심각함

Swift, SwiftUI 완전 괜찮은데?

애플에서 발표한지 2년이 다되어가는 기능을 두고 이제와서 좋다고 말하는데 어지간히 뒷북이긴 하지만 애플이 자존심을 버리고 CSS의 장점을 잘(?) 흡수해서 하나의 코드페이지에 통합한것은 늦었지만 훌륭한 작업이었다고 칭찬할만 하다고..

iOS만 지원하는 SwiftUI와 위의 멀티플랫폼 도구를 비교하는게 오류가 있을 수 있지만 UI 구성과 코드의 자연스러운 연결에 대한 부분만 본다면 SwiftUI가 가장 우수하지 않을까 하는게 최근 앱을 하나 만들어 보고 내린 결론. 물론 개인적인 생각!

SwiftUI 테스트 프로젝트

초심으로 돌아가 돈을 벌생각이 없는 무료앱을 하나 만들어봄. 대략 2주정도 걸렸고 익숙하지 않은 방법으로 화면을 만들어야 했지만 애플의 튜토리얼 프로젝트를 따라하다보니 위에 RN, Flutter에서 UI를 만들며 했던 경험들이 매우 도움이됨

https://developer.apple.com/tutorials/swiftui

위의 튜토리얼에서 iOS화면구성에 필요한 기본적인 컨트롤의 레이아웃을 구성하는 방법에 대한 정보를 얻을 수 있었고 여기에 더해 API통신(Alamofire), GoogleAnalytics등을 Pod으로 설치해서 프로젝트 생성

내연봉계산기

앱다운로드는 아래링크

https://apps.apple.com/kr/app/id1564866857

이 앱은 개인적으로 수년에 한번씩 만드는 테스트 프로젝트인데 새로운 개발 프레임워크를 테스트 할때마다 새로 만드는 앱. 해가 바꿜때마다 만들때마다 소득세를 포함한 각종 공제액의 비율이 달라져서 매년 업데이트를 해야만 해서 새로운 공부를 시작할때 유용하게 재사용하고 있음. 물론 완전히 새로 만드는거지만

결론

어느것이 더 좋다는 결론을 내리려고 하는것은 아니고 개인적으로 최근 수년간 Xcode를 그저 빌드 도구(RN, Flutter 역시 iOS 빌드는 Xcode로 한다)로만 사용하고 있었는데 멀티플랫폼에 대한 부담을 벗어버리니 Swift/SwiftUI가 개인적으로 다시 의미가 생겼다고나 할까?

SwuftUI가 UI빌딩과 메인터낸스에서 발군의 장점이 있는것과 동시에 그동안 깨닫지 못하고 있었던 빌드타임과 런타임성능이 RN, Flutter에 비해 현저하게 빠르다는것도 매우 큰 장점이다. 물론 멀티플랫폼을 지원하지 않는다는게 단점이라면… 그건 당연한거지만

20210501 박병일

React Native 다시 공부하기

React Native는 이미 2017년에 버즈아트에서 나름 빠르게 도입해서 프로젝트에 성공적으로 적용했던 적이 있었다. 링크참조(http://practical.kr/?cat=6) 그때 버전이 v0.45 수준이었는데 3년이 지난 지금도 React Native는 v0.61에 머물러 있다. 대체 언제쯤 v1.0을 내놓으려나…

2020년 현재 여전히 크로스(멀티)플랫폼(iOS, Android)을 지원하는것은 매력적이고 그동안 꽤 많은 기술적 진보가 있었을 것이라는 생각을 염두에 두고 다시 한번 공부를 시작해 볼까? 하는 생각에 연습용 프로젝트를 하나 만들기 시작했다. 이글을 쓰는 이유는 프로젝트를 만들고 보니 기억 나는게 하나도 없어서 뭘 했는지 정리하기 위함이다.

모바일 멀티플랫폼

잠시 멀티 플랫폼 이야기를 하고 넘어가보자. 최근 2~3년 사이에 모바일 플랫폼 개발과 관련한 프레임워크는 전통적인 Swift기반의 Xcode, Java & Kotlin 기반의 Android Studio와 더불어 Dart 기반의 Flutter, C# 기반의 Xamarin 등이 쏟아지며 개발툴 전성시대가 열린것 같다. 성능도 많은 향상을 보여서 거의 네이티브 성능을 따라오는 수준까지 도달한 것으로 보인다. 어떤것을 선택해도 크게 문제가 없을것으로 생각된다. 하지만 역시 가장 좋은것은 손에 익은것이 아닐까 싶다.

나 개인적으로는 오래도록 사용해온 Obj-C 기반의 Xcode가 가장 좋지만 이건 멀티 플랫폼이 아닌지라(iOS만지원) 제외하고 최근 2~3년간 JavaScript 특별히 Vue.js / Node.js를 사용해 오고 있었기 때문에 JS 기술을 그래도 활용할 수 있는 React Native에 끌리는건 당연한 선택일 수 밖에 없다. 하지만 처음 접하는 모바일 멀티 플랫폼 개발이라면 Dart/Flutter이 좀더 낫지 않을까 하는 생각인데 이유는 구글의 개발자 문서 지원이 매우 좋고 React Native에 비하여 좀 더 좋은 실행 성능을 내고 있다고 알려져 있기 때문이다.

Getting-Started

프로젝트 시작은 여기서 한다. Expo를 이용하는 방법과 Cli 툴을 이용하는 방법이 있는데 나는 Cli 툴을 이용하여 프로젝트를 생성 했다. Expo를 쓰면 폰에 직접 앱을 올려서 바로 결과를 볼 수 있고 Cli툴을 쓰면 Xcode 및 각종 도구를 깔아서 시뮬레이터에서 테스트를 할 수 있다. 나중에 스토어용으로 빌드를 하기 위해서 후자의 방법으로 설치하는 것이 좋다. 하지만 간단한 테스트는 Expo가 훨씬 편하다.

https://reactnative.dev/docs/getting-started

Navigation

앱을 만들려면 기본적으로 메뉴 시스템이 있어야 한다. 모바일 시스템에서 메뉴 시스템은 보통 Tabbar – Navigation, Drawer – Navigation 두가지 중에서 선택하는 것이 일반적인 선택이다. 한동안 Drawer 메뉴가 유행을 하다가 최근 다시 Tabbar 시스템이 유행인것 같아서 나는 Tabbar 시스템 기반으로 했다.

네비게이션 라이브러리는 ReactNavigation을 사용했다. 아마 개발자들이 가장 많이 사용하는 메뉴 시스템이고 Tabbar와 Drawer를 모두 지원한다.

https://reactnavigation.org/docs/getting-started

import React from 'react';
import {NavigationContainer} from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';

import Home from './src/Home';
import Profile from './src/Profile';
import Settings from './src/Settings';

const Tab = createBottomTabNavigator();

export default function App() {

  return (
    <NavigationContainer>
      <Tab.Navigator>
        <Tab.Screen name="Home" component={Home}/>
        <Tab.Screen name="Profile" component={Profile}/>
        <Tab.Screen name="Settings" component={Settings}/>
      </Tab.Navigator>
    </NavigationContainer>
  );
}

코드의 결과로 아래와 같은 메뉴 시스템이 나왔다. 메뉴에 아이콘을 넣거나 좀더 예쁘게 꾸미려면 https://reactnavigation.org/docs/tab-based-navigation 를 참조하자.

Rest API Communication

Rest API 서버에서 데이터를 가지고 와서 목록 형태로 보여주는 것은 axios를 이용한다. https://github.com/axios/axios 를 참조한다. 컴포넌트가 마운트 될때 API 서버에서 데이터를 가져와서 state에 저장했다.

import axios from "axios";

...

componentDidMount() {
 axios.get("https://jsonplaceholder.typicode.com/users")
  .then(res =>{
   this.setState({ persons:res.data });
  });
}

FlatList – 목록보여주기

모바일 화면의 대부분은 목록(List)이다. 상하스크롤을 통하여 데이터 리스트를 조회 하고 화면을 선택하면 상세화면으로 진입하는 구성이 대부분이다. 이 리스트는 스크롤이 계속되는 특성상 화면에 보이는 만큼만 메모리 관리를 하지 않으면 너무 많은 메모리를 사용해서 앱을 다은 시키는 원인이 된다. React Native의 FlatList는 자동으로 메모리 관리를 해주기 때문에 필수적으로 쓰는 컴포넌트이다.

대략 아래와 같이 연결한다.

function Item({item, navigation}) {
 return (
   <View>
    <Text>{item.name}</Text>
   </View>
 )
}
....

render() {
 return (
  <View>
   <FlatList
    data={this.state.persons}
    renderItem={({item})=><Item item={item}/>}
    keyExtractor={item=>item.id}
   />
  </View>
 )
}
FlatList 결과화면

상태관리(Store)

React Native의 상태 관리는 Redux로 하는것이 기본이다. 하지만 Redux의 구조와 사용법이 직관적이지 않아서 좀더 직관적으로 쓸 수 있는 MobX를 사용했다. Redux와 MobX의 비교와 관련해서 우아한 형제의 기술블로그에 좋은 자료가 있어서 링크에서 자세한 정보를 얻을 수 있다.

https://woowabros.github.io/experience/2019/01/02/kimcj-react-mobx.html

MobX는 매우 직관적으로 Store를 사용할 수 있는데 이것은 마치 Vue.js의 Store 처럼 단순하게 사용할 수 있다. 사실 그에 비하면 Redux는 너무 복잡한 구조를 가진것이 사실이다. 대략 아래와 같은 코드를 이용하여 두개의 페이지에서 동일한 값의 증가를 확인 할 수 있다.

import {observable} from 'mobx';

class CounterStore {
 @observable counter = 0;
 
 increment() {
  this.counter++;
 }

 decrement() {
  this.counter--;
 }
}
export default new CounterStore();
import React, {Component} from 'react';
import { observer } from 'mobx-react';
import { StyleSheet, Text, View, Button } from 'react-native';

import CounterStore from '../../mobx/store'

@observer
export default class HomeScreen extends Component {
 render() {
  return (
   <View >
    <Text style={{fontSize: 60}}>
     {CounterStore.counter}
    </Text>
    <Button
     title="Increase"
     onPress={() => CounterStore.increment()}
    />
   </View>
  )
 }
}

Source Code – GitHub

아래 링크에서 위의 셈플 프로젝트의 소스코드는 아래 링크에서 다운로드 할 수 있다.

https://github.com/bipark/react_native_study

관련 링크

React 스터디 – https://ko.reactjs.org/docs/hello-world.html

Components – https://reactnative.dev/docs/activityindicator

Navigation – https://reactnavigation.org/docs/getting-started

Axios – https://github.com/axios/axios

Awesome React Native – https://github.com/jondot/awesome-react-native

리액트 프로젝트에서 MobX 사용하기 – https://velog.io/@velopert/MobX-2-%EB%A6%AC%EC%95%A1%ED%8A%B8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90%EC%84%9C-MobX-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0-oejltas52z

React에서 Mobx 경험기 (Redux와 비교기) – https://woowabros.github.io/experience/2019/01/02/kimcj-react-mobx.html

카카오 로그인 모듈 – https://github.com/react-native-seoul/react-native-kakao-login