1. 네이티브 앱

Native App

네이티브 앱은 우리가 흔히 말하는 '어플리케이션'을 의미합니다. 모바일 기기에 최적화 된 언어로 개발된 앱으로 안드로이드로 개발 된 앱을 안드로이드 SDK를 이용해 Java(자바) 언어로 만드는 앱 IOS기반 SDK를 이용해 Swift(스위프트)로 만드는 대부분의 앱이 여기에 속함

 

네이티브 앱의 장점

  • 성능이 웹앱, 하이브리드 앱에 비하여 가장 높다.
  • 네이티브 API를 호출하여 사용함으로 플랫폼과 밀착되어 있다.
  • 해당 언어에 익숙하면 더 쉽게 접근가능.
  •  

네이티브 앱의 단점

  • 플랫폼에 한정적이다.
  • 언어에 제약적이다. 따라서 해당 언어와 플랫폼의 API를 다루는데 익숙해져야한다.

 

2. 모바일 웹앱

WEB + APP

웹앱은 모바일웹과 네이티브앱을 결합한 형태로 모바일웹의 특징을 가지면서 네이티브앱의 장점을 갖고 있습니다. 모바일 웹 보다는 조금 더 모바일에 최적화 된 앱을 의미 합니다. 웹앱도 모바일 웹 처럼 일반적인 웹기술로 개발되고 모바일 브라우저에서 실행되지만 풀 브라우저 방식이 아닌 단일 페이지 방식으로 화면을 진화해 속도가 빠르다.

 

모바일 웹 web이란

모바일 웹은 모바일에서 PC용 사이트의 글자폰트와 이미지, 터치 아이콘 플레시 등 데스크탑 브라우저에서 실행되는 기능을 모바일에 맞추어 표현한 사이트를 의미한다. 쉽게말해 PC용 홈페이지를 모바일 스크린의 크기에 맞춰 줄여 놓은 것이라고 생각하면된다.

 

모바일 웹앱의 장점

  • 웹사이트를 보는 것이기 때문에 따로 설치할 필요가 없다.
  • 모든 기기와 브라우저에서 접근가능
  • 별도 설치 및 승인과정이 필요치 않아 유지보수가 용이하다.

모바일 웹앱의 단점

  • 플랫폼 API 카메라등 사용할 수 없고 오로지, 브라우저 API만 사용할 수 있다.
  • 친화적인 터치앱을 개발하기가 약간 번거롭다.
  • 네이브티, 하이브리드 앱보다 실행이 까다롭다. (브라우저를 열고 검색해 들어가야한다.)

 

3. 하이브리드 앱

하이브리드 앱은 기본적으로 '네이티브 앱 + 웹앱 ' 이라고 생각하시면 쉽습니다. 일반적으로 네이티브웹에 웹 View를 띄워 웹앱을 실행시키는 것이 보현적이며 양쪽의 API를 모두 사용 가능

하이브리드 APP의 장점

  • 네이티브 API와 브라우저 API를 이용한 다양한 개발이 가능
  • 웹 개발 기술을 사용해 앱을 개발할 수 있다.
  • 한 번의 개발로 다수의 플랫폼 대응

하이브리드 APP의 단점

  • 네이티브 기능에 접근하기 위해선 네이티브 개발 지식이 결국 필요함.
  • 웹뷰에서 앱을 실행하는 경우이기 때문에 앱의 성능이 곧 브라우저의 성능.
  • UI 프레임 워크 도구를 사용하지 않는다면 개발자가 UI를 제작해야함.

2020년 개발자가 사용하는 웹 프레임워크 TOP5

  1. Vue.js
  2. React.js
    • UI를 구축하는데 널리 사용되는 JavaScript 라이브러리입니다. '구성요서'라고하는 작고 격리된 코드 조각에서 복잡한 UI를 구성할 수 있는 선언적이고 동적이며 유연한 JavaScript 라이브러리입니다. 대화형 UI를 만들고 앱을 각 상태에 대한 간단한 보기를 디자인합니다. 자체 상태 관리하는 캡슐화된 구성요소를 빌드 한 다음이를 구성하여 복잡한 UI를 만든다. 기존코드를 다시 작성하지 않고도 React에서 새로운 기능을 개발할수 있다.
  3. Angular
  4. Angular.js
  5. JQuery

2019년 하이브리드 앱 개발 프레임워크 TOP5

  1. React Native
    • 2013년 Facebook에서 출시했으며, 많은 앱 개발자들에게 선택받았습니다. JavaScript 기반의 오픈 소스 크로스 플랫폼 앱 개발 프레임워크로, 개발자는 더욱 짧은 개발 주기와 빠른 개발 속도로 고성능의 모바일 앱을 개발할 수 있게 되었습니다.
    • React Native는 JSX 기반(JavaScript-XML) 프레임워크라는 장점이 있습니다. 모바일 앱 개발을 위해 Swift나 Java와 같은 복잡한 프로그래밍 언어를 학습할 필요가 없지요. 프레임워크에서 React Native 코드를 네이티브 뷰로 변환한 다음 렌더링을 수행하므로 유저에게 네이티브와 같은 환경을 제공합니다.
  2. FLUTTER
  3. IONIC
  4. XAMARIN
  5. ADOBE PHONEGAP

 

 

'React' 카테고리의 다른 글

[React] 리액트의 정체를 알아보자! 리액트 란  (0) 2020.10.09
  • Left(int nCount)
    • 왼쪽기준으로 문자열 추출
  • Mid(int nFirst) const
  • Mid(int nFirst, int nCount)
    • nFirst 추출을 시작할 문자열 위치
    • nCount 추출할 문자의 갯수
  • Right(int nCount) const
    • nCount 오른쪽 기준 추출할 문자의 수

 

 

대소문자 변경

CString strFileNameParse = _T("abcd");

strFileNameParse.MakeUpper();//ABCD
strFileNameParse.MakeLower();//abcd

멀티 쓰레드(Thread)란

  • 하나의 프로세스를 다수의 실행 단위로 구분하여 자원을 공유하고 자원의 생성과 관리의 중복성을 최소화하여 수행 능력을 향상 시키는 것
  • 하나의 프로그램을 동시에 여러개의 일을 수행할수 있도록 해주는 것

멀티 쓰레드를 사용하는 이유

  • 프로세스를 이용하여 동시에 처리하던 일을 쓰레드로 구현할 경우 메모리공간과 시스템 자원 소모가 줄어듬
  • 전역 변수의 공간 또는 동적으로 할당된 공간인 힙(Heap) 영역을 이용하여 데이터를 주고 받을 수 있음. 그렇기 때문에 프로세스간 통신 방법에 비해 쓰레드 간의 통신 방법이 간단하다.(프로세스 통신방법이란?)
  • 쓰레드의 문맥 교환은 프로세스의 문맥 교환과는 달리 캐시 메모리를 비울 필요가 없다.(프로세스 문맥 교환이란??) 따라서 시스템의 처리량이 향상 되고 자원 소모가 줄어들어 자연스럽게 프로그램의 응답시간이 단축된다.
  • 이러한 장점 때문에 여러 프로세스로 할 수있는 작업들을 하나의 프로세스에서 여러 쓰레드로 나눠 수행하는 것

멀티 프로세스와 멀티 쓰레드의 차이점

  • 멀티 프로세스 : [데이터 영역, 힙, 스택] 영역 모두를 비공유
  • 멀티 쓰레드 : [데이터 영역, 힙, 스택] 영역 중 스택 영역만 비공유

멀티 쓰레딩의 장점

  • 프로세스의 생성은 많은 시간과 자원을 소비한다. 이러한 단점을 최소화 시킨 일종의 (경량화된 프로세스=쓰레드)이다.(한줄 요약)
  • 멀티 쓰레드에서 쓰레드간 스택 영역만 비공유하고 데이터 영역과 힙 영역을 공유한다.
  • 쓰레드의 생성 및 컨텍스트 스위칭은 프로세스의 생성 및 컨텍스트 스위칭보다 빠르다.(?)
  • 멀티 쓰레드 컨텍스트 스위칭(Context Switching)시 데이터 영역과 힙을 올리고 내릴 필요가 없다.
  • 데이터 영역과 힙 영역을 통해 데이터 교환이 가능하다.
  • 쓰레드 사이에서의 데이터 교환에서는 특별한 기법이 필요없다.

멀티 쓰레딩의 문제점

  • 서로 다른 쓰레드가 데이터와 힙 역역을 공유하기 때문에 어떤 쓰레드가 다른 쓰레드에서 사용중인 변수나 자료 구조에 접근하여 엉뚱한 값을 읽어오거나 수정할 수 있다. 따라서 동기화 작업이 필요하다.
  • 동기화를 통해 작업 순서 처리를 컨트롤 하고 공유자원에 대한 접근을 컨트롤 하지만 이로인해 병목현상이 발생하여 성능이 저하될 가능성이 높다.
  • 그러므로 과도한 락(Lock)으로 인한 병목 현상을 줄어야한다. 공유 자원이 아닌 부분은 동기화 처리를 할 필요가 없다. 즉, 동기화 처리가 필요한 부분에만 synchronuized 키워드를 통해 동기화를 한다. 불필요한 부분까지 동기화를 할 경우 쓰레드는 락(Lock)을 획득한 쓰레드가 종료하기 전까지 대기해야한다.

 

'개인공부 > ICT상식' 카테고리의 다른 글

[ICT상식] API 종류  (0) 2020.12.09
[REST] HTTP/HTTPS 와 REST API 개념  (0) 2020.11.29
[ICT상식] 데이터 베이스 + 기타 IT 상식  (0) 2020.11.07
[ICT 상식 : 운영체제]  (0) 2020.11.06
[ICT 상식 : 디지털 상식]  (0) 2020.11.06

 

 

오류해결 1)

  • stdafx.h에서 afxdao.h부분을 주석처리해준다.
//#ifndef _AFX_NO_DAO_SUPPORT
//#include <afxdao.h> //MFC DAO database classes
//#endif // !_AFX_NO_DAO_SUPPORT

오류해결 2)

  • 재정의된 부분의 이름을 모두 변경한다.
    • ADOCONNECT.h에서 msado15.dll import에서 no_namespace rename("redefinition명","adoredefinition") rename.........
# import "C:\Program Files (x86)\Common Files\System\ADO\msado15dll" no_namespace rename("EOF", "adoEOF") rename("DataTypeEnum", "adoDataTypeEnum") rename("FieldAttributeEnum", "adoFieldAttributeEnum") rename("ParameterDirectionEnum", "adoParameterDirectionEnum")  rename("RecordStatusEnum", "adoRecordStatusEnum") rename("EditModeEnum", "adoEditModeEnum") rename("LockTypeEnum", "adoLockTypeEnum") 
  • mdb 관련 정보 읽는 로직
void CTXTTEST00Dlg::OnBnClickedButton3()
{
	 
	//CADOConnect file;

	//file.OpenMDB(L"D:\\검수\\20201105mdb대소문자변경");
	CDaoDatabase* database = NULL;
	CDaoTableDef* tableDef = NULL;

	TCHAR mdb[256] = _T("D:\\검수\\20201105mdb대소문자변경\\Camera.mdb");

	TRY
	{
		//db 오픈
		database = new CDaoDatabase;
	database->Open(mdb);
	

	{
		//테이블 개수 확인
		int tableCnt = database->GetTableDefCount();

		CString strTableCnt;
		strTableCnt.Format(_T("테이블 개수 : %d"), tableCnt);
		//AfxMessageBox(strTableCnt);


		//전체 테이블 목록보기
		CString tableNames;
		for (int i = 0; i < tableCnt; i++)
		{
			//테이블 정보 가져오기
			CDaoTableDefInfo tableDefInfo;
			database->GetTableDefInfo(i, tableDefInfo, AFX_DAO_ALL_INFO);	//첫번째 테이블
			//CDaoQueryDefInfo quryinfo;
			//database->GetQueryDefInfo(i, quryinfo, AFX_DAO_PRIMARY_INFO);
			if (tableDefInfo.m_lAttributes & dbSystemObject)	//시스템 테이블인 경우
				tableNames += _T("시스템 테이블 : ");
			else
				tableNames += _T("사용자 테이블 : ");

			tableNames += tableDefInfo.m_strName;	//테이블 이름
			tableNames += _T("\n");
		}
		AfxMessageBox(tableNames);
	}
	



	//테이블 정보 보기
	{
		tableDef = new CDaoTableDef(database);
		tableDef->Open(_T("file1"));	//album이라는 테이블

		CString info = _T("");

		//테이블 이름
		info += tableDef->GetName();
		info += _T("\n");

		//테이블 생성일
		COleDateTime oleCTime = tableDef->GetDateCreated();
		CString createTime;
		createTime.Format(_T("생성일: %04d-%02d-%02d\n"), oleCTime.GetYear(), oleCTime.GetMonth(), oleCTime.GetDay());
		info += createTime;

		//테이블 마지막 수정일
		COleDateTime oleUTime = tableDef->GetDateLastUpdated();
		CString lastUpdatedTime;
		lastUpdatedTime.Format(_T("수정일: %04d-%02d-%02d\n"), oleUTime.GetYear(), oleUTime.GetMonth(), oleUTime.GetDay());
		info += lastUpdatedTime;

		//테이블 레코드 수
		CString recordCnt;
		recordCnt.Format(_T("레코드수: %ld\n"), tableDef->GetRecordCount());
		info += recordCnt;

		//테이블 필드 출력
		info += _T("필드정보\n");
		CDaoFieldInfo fieldInfo;
		int fieldCnt = tableDef->GetFieldCount();
		for (int i = 0; i < fieldCnt; i++)
		{
			tableDef->GetFieldInfo(i, fieldInfo, AFX_DAO_ALL_INFO);
			info += _T("\t");
			info += fieldInfo.m_strName;		//필드 이름
			info += _T(" : ");
			short nType = fieldInfo.m_nType;	//필드 타입
			switch (nType)
			{
			case dbBoolean: info += _T("BOOLEAN");	break;
			case dbByte: info += _T("BYTE");		break;
			case dbInteger: info += _T("INTEGER");	break;
			case dbLong: info += _T("LONG");		break;
			case dbSingle: info += _T("SINGLE");		break;
			case dbCurrency: info += _T("CURRENCY");	break;
			case dbDate: info += _T("DATE");		break;
			case dbDouble: info += _T("DOUBLE");		break;
			case dbText: info += _T("TEXT");		break;
			case dbLongBinary: info += _T("LONGBINARY");	break;
			case dbMemo: info += _T("MEMO");		break;
			}
			info += _T("\n");
		}

		//인덱스 필드 찾기
		info += _T("인덱스 필드\n");
		CDaoIndexInfo indexInfo;
		int indexCnt = tableDef->GetIndexCount();
		for (int i = 0; i < indexCnt; i++)
		{
			tableDef->GetIndexInfo(i, indexInfo);
			for (int j = 0; j < indexInfo.m_nFields; j++)
			{
				CString indexField = indexInfo.m_pFieldInfos[j].m_strName;
				info += _T("\t");
				info += indexField;
				info += _T("\n");
			}
		}

		AfxMessageBox(info);
	}


	//쿼리 실행
	{
		CDaoRecordset rs(database);
		rs.Open(AFX_DAO_USE_DEFAULT_TYPE, _T("select count(*) as cnt from file1"));	//쿼리 실행

		COleVariant var;
		rs.GetFieldValue(_T("cnt"), var);	//쿼리 값 획득
		rs.Close();

		CString value = convertString(var);
		AfxMessageBox(value);
	}

	//바인딩 쿼리 실행 : select
	{
		//바인딩 형식의 쿼리 저장
		CDaoQueryDef qd(database);
		/* qd.Create()의 첫번째 인수의 문자로 쿼리가 저장되며 qd.Append()로 저장이 완료됨.
		(영구저장되는 위치가 레지스트리 같긴한데 잘 모르겠습니다.)
		한번쓰는 임시 쿼리인 경우 NULL을 준후 qd.Append()를 안해주면 됩니다.*/
		qd.Create(NULL, _T("PARAMETERS [binding 1] INT; select * from file1 where 1 = [binding 1]"));
		//qd.Append();	//영구적인 쿼리 저장

		//바인딩
		COleVariant binding1((short)1);
		qd.SetParamValue(_T("[binding 1]"), binding1);

		//쿼리 실행
		CDaoRecordset rs(database);
		rs.Open(&qd);

		CString rst;
		int tempcntz = 0;
		while (!rs.IsEOF())
		{
			tempcntz++;
			if (tempcntz > 20000)
			{
				string zztemp = "123";
			}
			int cnt = rs.GetFieldCount();
			COleVariant var;
			for (int i = 0; i < cnt; i++)
			{
				rs.GetFieldValue(i, var);
				rst += convertString(var);
				rst += _T(", ");
			}
			rst += _T("\n");
			rs.MoveNext();	//scroll
		
		}
		AfxMessageBox(rst);

		qd.Close();
		//qd.m_pDAOQueryDef->Close();
	}
	}
		CATCH(CException, e) //예외처리 : 정확히는 CDaoException이지만 어짜피 CException 상속 클래스임.
	{
		TCHAR szCause[256];
		e->GetErrorMessage(szCause, 256);
		AfxMessageBox(szCause, MB_ICONERROR);
	}
	END_CATCH

		if (tableDef != NULL)
		{
			if (tableDef->IsOpen()) tableDef->Close();
			delete tableDef;
			tableDef = NULL;
		}
	if (database != NULL)
	{
		if (database->IsOpen()) database->Close();
		delete database;
		database = NULL;
	}


}

 

  • 중간에 mdb에서 가져온 COlecVariant를 CString으로 바꿔주는 함수
//COleVariant를 CString으로 변환해줄 함수
CString convertString(COleVariant& var)
{
	CString value;
	switch (var.vt)	//COleVariant를 CString으로 변경
	{
	case VT_EMPTY:
	case VT_NULL: value = _T("NULL");										break;
	case VT_I2: value.Format(_T("%hd"), V_I2(&var));						break;
	case VT_I4: value.Format(_T("%d"), V_I4(&var));						break;
	case VT_R4: value.Format(_T("%e"), (double)V_R4(&var));				break;
	case VT_R8: value.Format(_T("%e"), V_R8(&var));						break;
	case VT_CY: value = COleCurrency(var).Format();						break;
	case VT_DATE: value = COleDateTime(var).Format(_T("%m %d %y"));			break;
	case VT_BSTR: value = V_BSTRT(&var);									break;
	case VT_DISPATCH: value = _T("VT_DISPATCH");								break;
	case VT_ERROR: value = _T("VT_ERROR");									break;
	case VT_BOOL: V_BOOL(&var) ? value = _T("TRUE") : value = _T("FALSE");		break;
	case VT_VARIANT: value = _T("VT_VARIANT");									break;
	case VT_UNKNOWN: value = _T("VT_UNKNOWN");									break;
	case VT_I1: value = _T("VT_I1");										break;
	case VT_UI1: value.Format(_T("0x%02hX"), (unsigned short)V_UI1(&var));	break;
	case VT_UI2: value = _T("VT_UI2");										break;
	case VT_UI4: value = _T("VT_UI4");										break;
	case VT_I8: value = _T("VT_I8");										break;
	case VT_UI8: value = _T("VT_UI8");										break;
	case VT_INT: value = _T("VT_INT");										break;
	case VT_UINT: value = _T("VT_UINT");									break;
	case VT_VOID: value = _T("VT_VOID");									break;
	case VT_HRESULT: value = _T("VT_HRESULT");									break;
	case VT_PTR: value = _T("VT_PTR");										break;
	case VT_SAFEARRAY: value = _T("VT_SAFEARRAY");								break;
	case VT_CARRAY: value = _T("VT_CARRAY");									break;
	case VT_USERDEFINED: value = _T("VT_USERDEFINED");								break;
	case VT_LPSTR: value = _T("VT_LPSTR");									break;
	case VT_LPWSTR: value = _T("VT_LPWSTR");									break;
	case VT_FILETIME: value = _T("VT_FILETIME");								break;
	case VT_BLOB: value = _T("VT_BLOB");									break;
	case VT_STREAM: value = _T("VT_STREAM");									break;
	case VT_STORAGE: value = _T("VT_STORAGE");									break;
	case VT_STREAMED_OBJECT: value = _T("VT_STREAMED_OBJECT");							break;
	case VT_STORED_OBJECT: value = _T("VT_STORED_OBJECT");							break;
	case VT_BLOB_OBJECT: value = _T("VT_BLOB_OBJECT");								break;
	case VT_CF: value = _T("VT_CF");										break;
	case VT_CLSID: value = _T("VT_CLSID");									break;
	}
	WORD vt = var.vt;
	if (vt & VT_ARRAY)
	{
		vt = vt & ~VT_ARRAY;
		value = _T("Array of ");
	}
	if (vt & VT_BYREF)
	{
		vt = vt & ~VT_BYREF;
		value += _T("Pointer to ");
	}
	if (vt != var.vt)
	{
		switch (vt)
		{
		case VT_EMPTY: value += _T("VT_EMPTY");				break;
		case VT_NULL: value += _T("VT_NULL");				break;
		case VT_I2: value += _T("VT_I2");					break;
		case VT_I4: value += _T("VT_I4");					break;
		case VT_R4: value += _T("VT_R4");					break;
		case VT_R8: value += _T("VT_R8");					break;
		case VT_CY: value += _T("VT_CY");					break;
		case VT_DATE: value += _T("VT_DATE");				break;
		case VT_BSTR: value += _T("VT_BSTR");				break;
		case VT_DISPATCH: value += _T("VT_DISPATCH");			break;
		case VT_ERROR: value += _T("VT_ERROR");				break;
		case VT_BOOL: value += _T("VT_BOOL");				break;
		case VT_VARIANT: value += _T("VT_VARIANT");			break;
		case VT_UNKNOWN: value += _T("VT_UNKNOWN");			break;
		case VT_I1: value += _T("VT_I1");					break;
		case VT_UI1: value += _T("VT_UI1");				break;
		case VT_UI2: value += _T("VT_UI2");				break;
		case VT_UI4: value += _T("VT_UI4");				break;
		case VT_I8: value += _T("VT_I8");					break;
		case VT_UI8: value += _T("VT_UI8");				break;
		case VT_INT: value += _T("VT_INT");				break;
		case VT_UINT: value += _T("VT_UINT");				break;
		case VT_VOID: value += _T("VT_VOID");				break;
		case VT_HRESULT: value += _T("VT_HRESULT");			break;
		case VT_PTR: value += _T("VT_PTR");				break;
		case VT_SAFEARRAY: value += _T("VT_SAFEARRAY");			break;
		case VT_CARRAY: value += _T("VT_CARRAY");				break;
		case VT_USERDEFINED: value += _T("VT_USERDEFINED");		break;
		case VT_LPSTR: value += _T("VT_LPSTR");				break;
		case VT_LPWSTR: value += _T("VT_LPWSTR");				break;
		case VT_FILETIME: value += _T("VT_FILETIME");			break;
		case VT_BLOB: value += _T("VT_BLOB");				break;
		case VT_STREAM: value += _T("VT_STREAM");				break;
		case VT_STORAGE: value += _T("VT_STORAGE");			break;
		case VT_STREAMED_OBJECT: value += _T("VT_STREAMED_OBJECT");	break;
		case VT_STORED_OBJECT: value += _T("VT_STORED_OBJECT");		break;
		case VT_BLOB_OBJECT: value += _T("VT_BLOB_OBJECT");		break;
		case VT_CF: value += _T("VT_CF");					break;
		case VT_CLSID: value += _T("VT_CLSID");				break;
		}
	}
	return value;
}

MFC 기반의 MS SQL을 ADO OLE DB와 연결 중

#import "C:\PROGRAM FILES\COMMON FILES\SYSTEM\ADO\MSADO15.DLL" \
no_namespace rename("EOF", "EndOfFile")
[오류]
Cannot open
 include file: 'c:\project\debug\MSADO15.tlh'

 

해당 dll을 import가 안되는 오류 발생 

[해결방법]

  1. C/C++ -> 일반 -> 다중 프로세스 컴파일 YES(/MP)로 수정

2. C/C++ ->코드 일반화 -> 최소 리빌딩 (NO/GM-) 수정

3.#import "C:\PROGRAM FILES\COMMON FILES\SYSTEM\ADO\MSADO15.DLL" \
no_namespace rename("EOF", "EndOfFile") 를 atdafx.h의 전처리 맨 마지막에 설정한다. 

이유 : 너무 먼저 선언해버리면 window.h 와 같은 전처리기와 충돌발생

 

 

해당 dll 을 import 하면 _ConnectionPtr, _RecordsetPtr, _CommandPtr 3개의 타입을 사용 가능.

 

 

Visual Studio는 Compile시 multi-processor compilation을 지원한다.
processor는 각각 파일 하나씩을 담당하여 compile을 진행한다.
따라서 core가 많을수록 compile속도는 증가한다.

multi-processor compilation 옵션을 켰을 때
compile속도가 50초에서 6초로 줄어 들었다.

Project 의Property Pages에서
Configuration Properties
    -> C/C++
        ->General
            맨 밑의 Multi-processor Compilation을 YES로 변경

만약 Minimal Rebuild가 켜져 있을 경우 /MP가 무시되므로 아래와 같이 변경해준다.
Configuration Properties
    -> C/C++
        ->Code Generation
            Enable Minimal Rebuild를 No로 변경

 

MVC ( Model-View-Controller)

  • 개발 시 3가지 형태로 역할을 나누어 개발하는 방법론
  • 비즈니스 처리 로직사용자 인터페이스 요소들을 분리시켜 서로 영향없이 개발하기 수월하다는 장점

Model

  • "무엇"을 할 것인지를 정의 내부 비즈니스 로직을 처리하기 위한 역할
    • 처리되는 알고리즘, DB와 상호작용(CRUD Create Read Update Delete)

Controller

  • "어떻게" 처리할 지를 알려주는 역할 , 모바일에서 화면의 로직처리 부분입니다. 화면에서 사용자의 요청을 받아서 처리되는 부분을 구현하게 되며, 요청 내용을 분석해서 Model과 View에 업데이트 요청을 하게 됩니다.
  • 사용자로 부터의 입력을 받고 Model 또는 View중개인 역할

View 

  • 화면에 무엇인가를 보여주기위한 역할, 컨트롤러 하위에 종속되어, 모델이나 컨트롤러가 보여주려고 하는 모든 필요한 것들을 보여줌
  • 최종 사용자에게 무엇을 화면(UI)으로 보여줌

 

MVC의 한계

  • MVC에서 View는 Controller에 연결되어 화면을 구성하는 단위요소이므로 다수의 View들을 가질 수 있다.
  • Model은 Controller를 통해서 View와 연결되어지지만, 어떻게 Controller를 통해서 하나의 View에 연결될 수 있는 Model도 여러개가 될 수 있다.
  • 이러한 문제점을 해결하기 위해서 다양한 패턴을 파생시킴.

 

 

 

+ Recent posts