আইওএস নেটওয়ার্কিং অ্যাপ্লিকেশন (আরএসটি ক্লায়েন্ট) তৈরির জন্য সেরা স্থাপত্য পদ্ধতির


323

আমি কিছু অভিজ্ঞতার সাথে আইওএস বিকাশকারী এবং এই প্রশ্নটি আমার কাছে সত্যই আকর্ষণীয়। আমি এই বিষয়টিতে প্রচুর বিভিন্ন সংস্থান এবং উপকরণ দেখেছি, তবে তবুও আমি এখনও বিভ্রান্ত। কোনও আইওএস নেটওয়ার্ক অ্যাপ্লিকেশনটির জন্য সেরা আর্কিটেকচারটি কী? আমি বলতে চাইছি বেসিক অ্যাবস্ট্রাক ফ্রেমওয়ার্ক, প্যাটার্নগুলি, যা প্রতিটি নেটওয়ার্কিং অ্যাপ্লিকেশনের সাথে খাপ খায়, এটি কেবলমাত্র কয়েকটি অ্যাপ্লিকেশন বা কোনও জটিল আরএসইএস ক্লায়েন্ট রয়েছে কিনা app অ্যাপল MVCসমস্ত আইওএস অ্যাপ্লিকেশনগুলির জন্য একটি মৌলিক স্থাপত্য পদ্ধতির হিসাবে ব্যবহার করার পরামর্শ দেয় , তবে নেটওয়ার্ক লজিক কোডটি কোথায় রাখা উচিত এবং কীভাবে এটি সাধারণভাবে সংগঠিত করা যায় তাও MVCআধুনিক MVVMপ্যাটার্নগুলি নয়।

আমি ভালো কিছু বিকাশ প্রয়োজন MVCS( Sজন্য Service) এবং এই মধ্যে Serviceস্তর সব করা APIঅনুরোধ এবং অন্যান্য নেটওয়ার্কিং যুক্তি, যা দৃষ্টিভঙ্গি সত্যিই জটিল হতে পারে? কিছু গবেষণা করার পরে আমি এর জন্য দুটি প্রাথমিক পদ্ধতির সন্ধান পেয়েছি। এখানে ওয়েব-সার্ভিসে API(যেমন LoginRequestশ্রেণি বা PostCommentRequestশ্রেণি এবং এর মতো ) প্রতিটি নেটওয়ার্কের অনুরোধের জন্য একটি পৃথক শ্রেণি তৈরি করার পরামর্শ দেওয়া হয়েছিল যা বেস রিকোয়েস্টের অ্যাবস্ট্রাক্ট শ্রেণীর সমস্ত উত্তরাধিকার সূত্রে প্রাপ্ত হয় AbstractBaseRequestএবং কিছু বিশ্বব্যাপী নেটওয়ার্ক ম্যানেজার তৈরি করে যা সাধারণ নেটওয়ার্কিং কোডকে আবশ্যক করে এবং অন্যান্য পছন্দগুলি (এটি AFNetworkingকাস্টমাইজেশন হতে পারে বাRestKitটিউনিং, যদি আমাদের জটিল অবজেক্ট ম্যাপিং এবং অধ্যবসায় থাকে, বা এমনকি স্ট্যান্ডার্ড এপিআই সহ একটি নিজস্ব নেটওয়ার্ক যোগাযোগ বাস্তবায়ন)। তবে এই পদ্ধতির বিষয়টি আমার কাছে একটি ওভারহেড বলে মনে হচ্ছে। আরেকটি পন্থা কিছু Singleton থাকতে হয় APIডেস্প্যাচার বা প্রথম পদ্ধতির মধ্যে যেমন ম্যানেজার বর্গ, কিন্তু মত এই পরিচালকের ক্লাসের একটা নিদর্শন প্রকাশ্য পদ্ধতি হিসাবে যে অনুরোধ encapsulate প্রতি অনুরোধ ক্লাস তৈরি এবং পরিবর্তে: fetchContacts, loginUserপদ্ধতি, ইত্যাদি তো, সবচেয়ে ভাল এবং সঠিক উপায়? আমি জানি না এমন আরও আকর্ষণীয় পন্থা আছে কি?

এবং আমি কি এই সমস্ত নেটওয়ার্কিং স্টাফের মতো Service, বা NetworkProviderস্তর বা আমার MVCআর্কিটেকচারের উপরে যা কিছু আছে তার জন্য অন্য স্তর তৈরি করতে পারি , বা এই স্তরটি বিদ্যমান MVCস্তরগুলিতে ইন্টিগ্রেটেড (ইনজেকশনের) হওয়া উচিত Model? যেমন ?

আমি জানি যে সুন্দর পদ্ধতির উপস্থিতি রয়েছে, বা ফেসবুক ক্লায়েন্ট বা লিংকডইন ক্লায়েন্টের মতো মোবাইল দানব কীভাবে নেটওয়ার্কিং লজিকের তাত্পর্যপূর্ণ ক্রমবর্ধমান জটিলতার মোকাবেলা করতে পারে?

আমি জানি সমস্যার কোন সঠিক এবং আনুষ্ঠানিক উত্তর নেই। এই প্রশ্নের লক্ষ্য হ'ল অভিজ্ঞ আইওএস বিকাশকারীদের কাছ থেকে সবচেয়ে আকর্ষণীয় পন্থা সংগ্রহ করা । সেরা প্রস্তাবিত পদ্ধতির গ্রহণযোগ্য হিসাবে চিহ্নিত করা হবে এবং খ্যাতি অনুদানের সাথে ভূষিত করা হবে, অন্যরা উজ্জীবিত হবে। এটি বেশিরভাগই তাত্ত্বিক এবং গবেষণামূলক প্রশ্ন is আমি আইওএসে নেটওয়ার্কিং অ্যাপ্লিকেশনগুলির জন্য বেসিক, বিমূর্ত এবং সঠিক স্থাপত্য পদ্ধতির বিষয়টি বুঝতে চাই understand আমি অভিজ্ঞ বিকাশকারীদের কাছ থেকে বিস্তারিত ব্যাখ্যা আশা করি।


14
এটি কি "শপিং লিস্ট" প্রশ্ন নয়? আমার কাছে কেবল একটি প্রশ্ন ছিল যা নরকে ভোট দিয়েছিল এবং বন্ধ করে দেওয়া হয়েছিল কারণ এটি "সবচেয়ে ভাল কি" টাইপ প্রশ্নগুলি অনেকগুলি বেআইনী বিতর্ক ছড়ায়। এই শপিং লিস্টের প্রশ্নটি কীভাবে উত্তম ও অনুগ্রহের যোগ্য একটি ভাল প্রশ্ন তৈরি করে যখন অন্যরা বন্ধ হয়ে যায়?
অ্যালভিন থম্পসন

1
সাধারণত নেটওয়ার্ক যুক্তি নিয়ন্ত্রকের মধ্যে চলে যেত, যা কোনও মডেল অবজেক্টকে পরিবর্তন করে কোনও প্রতিনিধি বা পর্যবেক্ষককে অবহিত করবে।
17:51

1
খুব আকর্ষণীয় প্রশ্ন এবং উত্তর। আইওএস কোডিংয়ের 4 বছর পরে এবং অ্যাপটিতে একটি নেটওয়ার্ক স্তর যুক্ত করার সর্বাধিক সুন্দর উপায় সন্ধান করার চেষ্টা করছেন। কোন নেটওয়ার্ক রিকোয়েস্ট পরিচালনার দায়িত্ব কোন শ্রেণীর হওয়া উচিত? নীচের উত্তরগুলি সত্যই প্রাসঙ্গিক। আপনাকে ধন্যবাদ
darksider

@ জো ব্লো এটি সত্য নয়। মোবাইল অ্যাপ্লিকেশন শিল্প এখনও সার্ভার-ক্লায়েন্ট যোগাযোগগুলিতে নির্ভর করে।
অপমান

উত্তর:


327

I want to understand basic, abstract and correct architectural approach for networking applications in iOS: কোনও অ্যাপ্লিকেশন আর্কিটেকচার তৈরির জন্য কোনও "সেরা", বা "সবচেয়ে সঠিক" পন্থা নেই। এটি একটি খুব সৃজনশীল কাজ। আপনার সর্বদা সবচেয়ে সহজ এবং প্রসারিত আর্কিটেকচারটি বেছে নেওয়া উচিত, যা কোনও বিকাশকারী, যারা আপনার প্রকল্পে বা আপনার দলের অন্য বিকাশকারীদের জন্য কাজ শুরু করে তাদের পক্ষে পরিষ্কার হবে, তবে আমি সম্মত হই যে, "ভাল" এবং "খারাপ" হতে পারে "আর্কিটেকচার।

আপনি বলেছেন: গেটওয়ে , লেয়ার সুপারটাইপ , বিশেষ কেস ,collect the most interesting approaches from experienced iOS developers :, আমার ধারণাটি আমার কাছে সবচেয়ে আকর্ষণীয় বা সঠিক নয় বলে মনে হয় না তবে আমি এটি বেশ কয়েকটি প্রকল্পে ব্যবহার করেছি এবং এতে সন্তুষ্ট। এটি আপনি উপরে উল্লিখিতগুলির একটি হাইব্রিড পদ্ধতি এবং আমার নিজের গবেষণামূলক প্রচেষ্টার উন্নতিও রয়েছে। বিল্ডিং পদ্ধতির সমস্যাগুলির মধ্যে আমি আকর্ষণীয়, যা বেশ কয়েকটি সুপরিচিত নিদর্শন এবং প্রতিমাগুলির সমন্বয় করে। আমি মনে করি ফাউলারের প্রচুর এন্টারপ্রাইজ নিদর্শনগুলি মোবাইল অ্যাপ্লিকেশনগুলিতে সফলভাবে প্রয়োগ করা যেতে পারে। এখানে সর্বাধিক আকর্ষণীয়গুলির একটি তালিকা রয়েছে, যা আমরা কোনও আইওএস অ্যাপ্লিকেশন আর্কিটেকচার তৈরি করার জন্য আবেদন করতে পারি ( আমার মতে ): পরিষেবা স্তর , কাজের ইউনিট , রিমোট ফ্যাসাদ , ডেটা ট্রান্সফার অবজেক্ট , ডোমেন মডেল । আপনার সর্বদা সঠিকভাবে একটি মডেল স্তর ডিজাইন করা উচিত এবং অধ্যবসায়ের বিষয়ে সর্বদা ভুলবেন না (এটি আপনার অ্যাপের কার্যকারিতা উল্লেখযোগ্যভাবে বাড়িয়ে তুলতে পারে)। আপনি Core Dataএই জন্য ব্যবহার করতে পারেন । তবে আপনাকে ভুলে যাওয়া উচিত নয় , এটি Core Dataকোনও ওআরএম বা একটি ডাটাবেস নয়, তবে এটির একটি ভাল বিকল্প হিসাবে অধ্যবসায়ের সাথে একটি অবজেক্ট গ্রাফ ম্যানেজার। সুতরাং, খুব প্রায়ই Core Dataআপনার প্রয়োজনের জন্য খুবই ভারী হতে পারে এবং আপনি এই ধরনের নতুন সমাধান তাকান পারেন অধিরাজ্যCouchbase লাইট , অথবা আপনার নিজের লাইটওয়েট বস্তুর ম্যাপিং / অধ্যবসায় স্তর, বিল্ড কাঁচা SQLite বা উপর ভিত্তি করে LevelDB। এছাড়াও আমি আপনাকে ডোমেন চালিত ডিজাইন এবং সিকিউআরএসের সাথে নিজেকে পরিচিত করার পরামর্শ দিচ্ছি

প্রথমে, আমি মনে করি, নেটওয়ার্কিংয়ের জন্য আমাদের আরও একটি স্তর তৈরি করা উচিত , কারণ আমরা ফ্যাট কন্ট্রোলার বা ভারী, অভিভূত মডেলগুলি চাই না। আমি সেগুলিতে বিশ্বাস করি নাfat model, skinny controller জিনিসগুলিতে । কিন্তু আমি বিশ্বাস করি যে skinny everything, পদ্ধতি কারণ বর্গ চর্বি হওয়া উচিত, কি কখনো। সমস্ত নেটওয়ার্কিংকে সাধারণত ব্যবসায় যুক্তি হিসাবে বিমূর্ত করা যায়, ফলস্বরূপ আমাদের আরও একটি স্তর থাকা উচিত, যেখানে আমরা এটি রাখতে পারি। পরিষেবা স্তর যা আমাদের প্রয়োজন:

It encapsulates the application's business logic,  controlling transactions 
and coordinating responses in the implementation of its operations.

আমাদের MVCরাজ্যে Service Layerডোমেন মডেল এবং নিয়ন্ত্রণকারীদের মধ্যে মধ্যস্থতার মতো কিছু is এই পদ্ধতির এমভিসিএস নামে একটি পরিবর্তনের অনুরূপ প্রকরণ রয়েছে যেখানে এStore আসলে আমাদের Serviceস্তর রয়েছে। Storeমডেল দৃষ্টান্ত এবং হ্যান্ডলগুলি নেটওয়ার্কিং, ক্যাশে ইত্যাদি আমি যে আপনি উল্লেখ করতে চান vends করা উচিত নয় আপনার সেবা স্তর সব আপনার নেটওয়ার্কিং এবং ব্যবসা লজিক লিখুন। এটি একটি খারাপ নকশা হিসাবে বিবেচনা করা যেতে পারে। অ্যানিমিক এবং ধনী ডোমেন মডেলগুলি আরও তথ্যের জন্য দেখুন । কিছু পরিষেবা পদ্ধতি এবং ব্যবসায়িক যুক্তি মডেলটিতে পরিচালনা করা যায়, সুতরাং এটি "ধনী" (আচরণ সহ) মডেল হবে।

আমি সর্বদা দুটি গ্রন্থাগার ব্যবহার করি: এএফ নেটওয়ার্কিং ২.০ এবং রিঅ্যাকটিভ কোকোয়া । আমি মনে করি যে এটি কোনও আধুনিক অ্যাপ্লিকেশনটির জন্য অবশ্যই আবশ্যক যা নেটওয়ার্ক এবং ওয়েব-পরিষেবাগুলির সাথে যোগাযোগ করে বা জটিল ইউআই যুক্তিযুক্ত।

স্থাপত্য

প্রথমে আমি একটি সাধারণ APIClientশ্রেণি তৈরি করি , এটি এএফএইচটিটিপিএসসেশন ম্যানেজারের একটি সাবক্লাস । এটি অ্যাপ্লিকেশনটির সমস্ত নেটওয়ার্কিংয়ের একটি ওয়ার্কহর্স: সমস্ত পরিষেবা শ্রেণিগুলিতে এটিতে সত্যিকারের REST অনুরোধগুলি প্রেরণ করা হয়। এটিতে এইচটিটিপি ক্লায়েন্টের সমস্ত কাস্টমাইজেশন রয়েছে যা আমার বিশেষ অ্যাপ্লিকেশনটিতে প্রয়োজন: এসএসএল পিনিং, ত্রুটি প্রক্রিয়াকরণ এবং NSErrorবিশদ ব্যর্থতার কারণ এবং সমস্তটির বিবরণ সহ সরল বস্তু তৈরি করাAPI সাথে এবং সংযোগ ত্রুটির (যেমন ক্ষেত্রে নিয়ামক সঠিক বার্তা প্রদর্শন করতে সক্ষম হবেন) ব্যবহারকারী), অনুরোধ এবং প্রতিক্রিয়া সিরিয়ালাইজার, HTTP শিরোনাম এবং অন্যান্য নেটওয়ার্ক-সম্পর্কিত স্টাফ সেট করে। তারপর আমি কথাটি subservices বা সঠিকভাবে সব API অনুরোধে ভাগ, microservices : UserSerivces, CommonServices, SecurityServices,FriendsServicesএবং তাই, সেই অনুসারে তারা ব্যবসায়িক যুক্তি প্রয়োগ করে। এই মাইক্রোসার্ভেসগুলির প্রতিটি পৃথক শ্রেণি। তারা, একসাথে, একটি গঠন Service Layer। এই ক্লাসগুলিতে প্রতিটি এপিআই অনুরোধের জন্য পদ্ধতি থাকে, ডোমেন মডেলগুলি প্রসেস করে এবং সর্বদা RACSignalপার্স করা প্রতিক্রিয়া মডেল বা NSErrorকলারকে একটি ফেরত দেয়।

আমি উল্লেখ করতে চাই যে আপনার যদি জটিল মডেল সিরিয়ালাইজেশন যুক্তি থাকে - তবে এর জন্য আরও একটি স্তর তৈরি করুন: ডেটা ম্যাপারের মতো কিছু তবে সাধারণ যেমন জেএসএন / এক্সএমএল -> মডেল ম্যাপার। যদি আপনার ক্যাশে থাকে: তবে এটিকে একটি পৃথক স্তর / পরিষেবা হিসাবে তৈরি করুন (আপনার ব্যবসায়ের যুক্তি কেচিংয়ের সাথে মিশ্রিত করা উচিত নয়)। কেন? কারণ সঠিক ক্যাচিং স্তরটি তার নিজস্ব গটছগুলির সাথে বেশ জটিল হতে পারে। বৈধ, অনুমানযোগ্য ক্যাচিং যেমন লোকেদের উপর ভিত্তি করে অনুমানগুলি সহ এককভাবে ক্যাচিং পেতে লোকে জটিল যুক্তি প্রয়োগ করে। আপনি আরও বুঝতে কার্লোস নামক এই সুন্দর লাইব্রেরি সম্পর্কে পড়তে পারেন । এবং ভুলে যাবেন না যে কোর ডেটা আপনাকে সমস্ত ক্যাশে সম্পর্কিত সমস্যাটিতে সত্যই সহায়তা করতে পারে এবং আপনাকে কম যুক্তি লেখার অনুমতি দেবে। এছাড়াও, যদি আপনার কাছে NSManagedObjectContextসার্ভারের অনুরোধগুলির মডেলগুলির মধ্যে কিছু যুক্তি থাকে তবে আপনি ব্যবহার করতে পারেনসংগ্রহস্থল প্যাটার্ন, যা যুক্তিকে পৃথক করে যা ডেটাটি পুনরুদ্ধার করে এবং মডেলটিতে কাজ করে এমন ব্যবসায়িক যুক্তি থেকে সত্তা মডেলটিতে এটি ম্যাপ করে। সুতরাং, আপনার কাছে কোর ডেটা ভিত্তিক আর্কিটেকচার থাকার পরেও রেপোজিটরি প্যাটার্নটি ব্যবহার করার পরামর্শ দিচ্ছি। সংগ্রহস্থলের প্রয়োগ করতে পারেন বিমূর্ত জিনিস, মত NSFetchRequest, NSEntityDescription, NSPredicateএবং তাই মত প্লেইন পদ্ধতি উপর getবা put

পরিষেবা স্তরটিতে এই সমস্ত ক্রিয়াকলাপের পরে, কলার (ভিউ কন্ট্রোলার) প্রতিক্রিয়া সহ কিছু জটিল অ্যাসিনক্রোনাস স্টাফ করতে পারে: আদিমদের সহায়তায় সিগন্যাল ম্যানিপুলেশনস, চেইনিং, ম্যাপিং ইত্যাদি ReactiveCocoa, বা কেবল এটিতে সাবস্ক্রাইব করুন এবং ফলাফলটিতে ফলাফল দেখান । আমি উদ্বুদ্ধ নির্ভরতা ইনজেকশন এই সব সেবা শ্রেণীর আমার মধ্যে APIClient, যা সংশ্লিষ্ট মধ্যে একটি বিশেষ সেবা কল অনুবাদ করবে GET, POST, PUT, DELETE, ইত্যাদি বিশ্রাম শেষবিন্দু করার অনুরোধ। এই ক্ষেত্রে APIClientসব কন্ট্রোলার পরোক্ষভাবে পাস করা হয়েছে, আপনি এই একটি ওভার parametrised সঙ্গে স্পষ্ট করে তুলতে পারে APIClientসেবা ক্লাস। আপনি যদি বিভিন্ন কাস্টমাইজেশন ব্যবহার করতে চান তবে এটি অর্থবোধ করতে পারেAPIClientনির্দিষ্ট পরিষেবা ক্লাসের জন্য, তবে আপনি যদি কিছু কারণে অতিরিক্ত অনুলিপি চান না বা আপনি নিশ্চিত হন যে আপনি সর্বদা একটি নির্দিষ্ট উদাহরণ (স্বনির্ধারণ ব্যতীত) ব্যবহার করবেন APIClient- এটি একটি সিঙ্গলটন করুন, তবে করবেন না, দয়া করে না 'টি সিলেটন হিসাবে পরিষেবা ক্লাস তৈরি করে।

তারপরে ডিআই সহ প্রতিটি ভিউ কন্ট্রোলার তার প্রয়োজন মতো পরিষেবা শ্রেণিকে ইনজেকশন দেয়, উপযুক্ত পরিষেবা পদ্ধতিগুলিকে কল করে এবং ইউআই যুক্তির সাথে তাদের ফলাফলগুলি রচনা করে। নির্ভরতা ইনজেকশনের জন্য আমি ব্লাডম্যাগিক বা আরও শক্তিশালী ফ্রেমওয়ার্ক টাইফুন ব্যবহার করতে চাই । আমি কখনও সিলেটলেটস, গড APIManagerWhateverক্লাস বা অন্যান্য ভুল জিনিস ব্যবহার করি না । কারণ আপনি যদি আপনার ক্লাসকে কল করেন তবে WhateverManagerএটির উদ্দেশ্যটি আপনি জানেন না তার থেকে এটি ইঙ্গিত করে এবং এটি একটি খারাপ ডিজাইনের পছন্দ । সিঙ্গলেটগুলিও একটি বিরোধী-প্যাটার্ন এবং বেশিরভাগ ক্ষেত্রে (বিরল ব্যতীত) একটি ভুল সমাধান। নিম্নলিখিত একক তিনটি মানদণ্ড সন্তুষ্ট হলেই সিঙ্গলটন বিবেচনা করা উচিত:

  1. একক উদাহরণের মালিকানা যথাযথভাবে অর্পণ করা যায় না;
  2. অলস সূচনাটি কাম্য;
  3. বৈশ্বিক অ্যাক্সেস অন্যথায় সরবরাহ করা হয় না।

আমাদের ক্ষেত্রে একক উদাহরণের মালিকানা কোনও সমস্যা নয় এবং আমরা আমাদের গড ম্যানেজারকে পরিষেবাগুলিতে বিভক্ত করার পরে আমাদের বিশ্বব্যাপী অ্যাক্সেসের দরকারও নেই, কারণ এখন কেবলমাত্র এক বা একাধিক নিবেদিত নিয়ামকদের একটি নির্দিষ্ট পরিষেবা প্রয়োজন (যেমন UserProfileনিয়ন্ত্রণকারী প্রয়োজন)UserServices এবং তাই) ।

আমাদের সর্বদা SOLID এS নীতির প্রতি শ্রদ্ধা করা উচিত এবং উদ্বেগের বিভাজন ব্যবহার করা উচিত , সুতরাং আপনার সমস্ত পরিষেবা পদ্ধতি এবং নেটওয়ার্ক কলগুলি একটি শ্রেণিতে রাখবেন না, কারণ এটি পাগল, বিশেষত যদি আপনি একটি বৃহত এন্টারপ্রাইজ অ্যাপ্লিকেশন বিকাশ করেন। এজন্য আমাদের নির্ভরতা ইনজেকশন এবং পরিষেবাগুলির পদ্ধতির বিষয়টি বিবেচনা করা উচিত। আমি এই পদ্ধতিকে আধুনিক এবং পোস্ট-ওও হিসাবে বিবেচনা করি । এই ক্ষেত্রে আমরা আমাদের অ্যাপ্লিকেশনটিকে দুটি ভাগে বিভক্ত করেছি: নিয়ন্ত্রণ যুক্তি (নিয়ন্ত্রণকারী এবং ইভেন্ট) এবং পরামিতিগুলি।

এক ধরণের পরামিতি সাধারণ "ডেটা" পরামিতি হবে। এটিই আমরা ফাংশনগুলির চারপাশে পাস, হেরফের, সংশোধন, অবিরাম থাকা ইত্যাদি These এগুলি সত্তা, সমষ্টি, সংগ্রহ, কেস ক্লাস। অন্য ধরণের হবে "পরিষেবা" পরামিতি। এগুলি এমন ক্লাস যা ব্যবসায় যুক্তিকে আবদ্ধ করে, বাহ্যিক সিস্টেমের সাথে যোগাযোগের অনুমতি দেয়, ডেটা অ্যাক্সেস সরবরাহ করে।

উদাহরণস্বরূপ এখানে আমার স্থাপত্যের একটি সাধারণ কর্মপ্রবাহ রয়েছে। ধরা যাক আমাদের একটি আছে FriendsViewControllerযা ব্যবহারকারীর বন্ধুদের তালিকা প্রদর্শন করে এবং আমাদের বন্ধুদের থেকে অপসারণের বিকল্প রয়েছে have আমি আমার FriendsServicesক্লাসে একটি পদ্ধতি তৈরি করি যার নাম:

- (RACSignal *)removeFriend:(Friend * const)friend

Friendকোনও মডেল / ডোমেন অবজেক্টটি কোথায় (বা Userতাদের যদি একই বৈশিষ্ট্য থাকে তবে এটি কেবল একটি বস্তু হতে পারে )। Underhood এই পদ্ধতি পার্স Friendথেকে NSDictionaryতাদেরকে JSON প্যারামিটার friend_id, name, surname, friend_request_idইত্যাদি। আমি সর্বদা এই ধরণের বয়লারপ্লেটের জন্য এবং আমার মডেল স্তরের (পিছনে এবং পিছনে পার্সিং, জেএসএন-তে নেস্টেড অবজেক্ট হায়ারারচি পরিচালনা করে এবং অন্যান্য) জন্য মেন্টল লাইব্রেরিটি সর্বদা ব্যবহার করি । পার্স পরে কল APIClient DELETEপ্রকৃত বিশ্রাম অনুরোধ এবং আয় করতে পদ্ধতি Responseমধ্যে RACSignalকলারের কাছে (FriendsViewController আমাদের ক্ষেত্রে) ব্যবহারকারী বা যাই হোক না কেন জন্য উপযুক্ত বার্তা প্রদর্শন করে।

আমাদের অ্যাপ্লিকেশনটি যদি খুব বড় একটি হয় তবে আমাদের যুক্তি আরও স্পষ্ট করে আলাদা করতে হবে। উদাহরণস্বরূপ, এটির সাথে সর্বদা মিশ্রিত করা Repositoryবা মডেল যুক্তি যুক্ত করা ভাল নয় Service। আমি যখন আমার পদ্ধতির বর্ণনা দিয়েছিলাম তখন আমি বলেছিলাম যে removeFriendপদ্ধতিটি Serviceস্তরে থাকা উচিত , তবে আমরা যদি আরও পেডেন্টিক হব তবে আমরা লক্ষ্য করতে পারি যে এটি আরও ভাল Repository। আসুন রিপোজিটরিটি কী তা মনে রাখা যাক। এরিক ইভান্স এটিকে তাঁর বই [ডিডিডি] থেকে সুনির্দিষ্ট বিবরণ দিয়েছিল:

একটি সংগ্রহস্থল একটি ধারণামূলক সেট হিসাবে নির্দিষ্ট ধরণের সমস্ত অবজেক্টকে উপস্থাপন করে। এটি আরও বিস্তৃত অনুসন্ধানের ক্ষমতা ব্যতীত সংগ্রহের মতো কাজ করে।

সুতরাং, একটি Repositoryমূলত একটি মুখবন্ধ যা ডেটা / অবজেক্টগুলিতে অ্যাক্সেস সরবরাহ করতে সংগ্রহ শৈলী শব্দার্থক (যোগ করুন, আপডেট করুন, সরান) ব্যবহার করে। কেন যখন তোমার মত কিছু আছে এটা getFriendsList, getUserGroups, removeFriendআপনি এটা করতে পারেন Repositoryকারণ সংগ্রহ মত শব্দার্থবিদ্যা প্রশংসনীয় এখানে পরিষ্কার করা হয়। এবং কোড এর মতো:

- (RACSignal *)approveFriendRequest:(FriendRequest * const)request;

অবশ্যই এটি একটি ব্যবসায়ের যুক্তি, কারণ এটি প্রাথমিক CRUDক্রিয়াকলাপের বাইরে এবং দুটি ডোমেন অবজেক্ট ( Friendএবং Request) সংযুক্ত করে, এজন্যই এটি স্তরতে রাখা উচিত Service। এছাড়াও আমি লক্ষ করতে চাই: অপ্রয়োজনীয় বিমূর্ততা তৈরি করবেন না । এই সমস্ত পদ্ধতির বুদ্ধিমানের সাথে ব্যবহার করুন। কারণ আপনি যদি আপনার অ্যাপ্লিকেশনটিকে বিমূর্ততা দিয়ে অভিভূত করেন তবে এটির দুর্ঘটনাজনিত জটিলতা বৃদ্ধি পাবে এবং জটিলতা আরও সমস্যার সৃষ্টি করবে সফ্টওয়্যার সিস্টেমে অন্য যে কোনও কিছুর চেয়ে software

আমি আপনাকে একটি "পুরাতন" অবজেক্টিভ-সি উদাহরণ বর্ণনা করেছি তবে এই পদ্ধতিকে আরও অনেক উন্নতির সাথে সুইফট ভাষার পক্ষে খুব সহজেই মানিয়ে নেওয়া যেতে পারে, কারণ এতে আরও কার্যকর বৈশিষ্ট্য এবং কার্যকরী চিনি রয়েছে। আমি এই লাইব্রেরিটি ব্যবহার করার জন্য অত্যন্ত পরামর্শ দিচ্ছি: মোয়া । এটি আপনাকে আরও মার্জিত APIClientস্তর তৈরি করতে দেয় (আপনার স্মরণে আমাদের ওয়ার্কহর্স)। এখন আমাদের APIClientসরবরাহকারী একটি প্রকারের প্রোটোকল অনুসারে এক্সটেনশান এবং ডেস্ট্রাকচারিং প্যাটার্ন মেলাকে কাজে লাগাতে একটি মান ধরণের (এনাম) হবে। সুইফ্ট এনামগুলি + প্যাটার্নের মিলটি ক্লাসিক ফাংশনাল প্রোগ্রামিংয়ের মতো বীজগণিত ডেটা টাইপ তৈরি করতে দেয় । আমাদের মাইক্রোসার্ভিসেসগুলি এই উন্নত APIClientসরবরাহকারীটিকে যথারীতি উদ্দেশ্যমূলক-সি পদ্ধতির মতো ব্যবহার করবে । পরিবর্তে মডেল স্তরের জন্য Mantleআপনি অবজেক্টম্যাপার লাইব্রেরিটি ব্যবহার করতে পারেনঅথবা আমি আরও মার্জিত এবং ক্রিয়ামূলক আরগো গ্রন্থাগার ব্যবহার করতে চাই ।

সুতরাং, আমি আমার সাধারণ স্থাপত্য পদ্ধতির বর্ণনা দিয়েছি, যা কোনও অ্যাপ্লিকেশনের জন্য মানিয়ে নেওয়া যেতে পারে, আমি মনে করি। অবশ্যই আরও অনেক উন্নতি হতে পারে। আমি আপনাকে ফাংশনাল প্রোগ্রামিং শেখার পরামর্শ দিচ্ছি, কারণ আপনি এটি থেকে প্রচুর উপকৃত হতে পারেন, তবে এটির সাথে খুব বেশি দূরেও যান না। অতিরিক্ত, ভাগ করা, বৈশ্বিক পরিবর্তনীয় অবস্থা নির্মূল করা, অপরিবর্তনীয় ডোমেন মডেল তৈরি করা বা বাহ্যিক পার্শ্ব-প্রতিক্রিয়া ছাড়াই খাঁটি ফাংশন তৈরি করা সাধারণত একটি ভাল অভ্যাস এবং নতুন Swiftভাষা এটিকে উত্সাহ দেয়। তবে সর্বদা মনে রাখবেন, ভারী খাঁটি কার্যকরী নিদর্শনগুলি সহ বিভাগ-তাত্ত্বিক পদ্ধতির সাথে আপনার কোডটি ওভারলোড করা একটি খারাপ ধারণা, কারণ অন্যান্য বিকাশকারীরা আপনার কোডটি পড়তে এবং সমর্থন করবে এবং তারা হতাশ বা ভয়ঙ্কর হতে পারেprismatic profunctorsএবং আপনার অপরিবর্তনীয় মডেল এ জাতীয় ধরণের জিনিস। একই জিনিস ReactiveCocoa: RACifyআপনার কোড খুব বেশি করবেন না , কারণ এটি সত্যিই দ্রুত অপঠনযোগ্য হয়ে উঠতে পারে, বিশেষত নতুনদের জন্য। এটি যখন আপনার লক্ষ্যগুলি এবং যুক্তিগুলি সত্যিই সরল করতে পারে তখন এটি ব্যবহার করুন।

তাই read a lot, mix, experiment, and try to pick up the best from different architectural approaches,। আমি আপনাকে দিতে পারি এটি সেরা পরামর্শ।


এছাড়াও একটি আকর্ষণীয় এবং দৃ approach় পদ্ধতির। ধন্যবাদ।
মূলধারার

1
@darksider আমি ইতিমধ্যে আমার উত্তর লিখেছিলেন করেছি: "` আমি singletons, ঈশ্বর APIManagerWhatever বর্গ বা অন্যান্য ভুল কাপড় ব্যবহার না কারণ Singleton (বিরল বেশী ব্যতীত) বিরোধী প্যাটার্ন, এবং বেশিরভাগ ক্ষেত্রেই ভুল সমাধান। ". I don't like singletons. I have an opinion that if you decided to use singletons in your project you should have at least three criteria why you do this (I edited my answer). So I inject them (lazy of course and not each time, but একবার `) যে নিয়ামক হবে।
Oleksandr Karaberov

14
হাই @ অ্যালেক্সান্ডার গিটহাবের কোনও উদাহরণ প্রকল্প আছে আপনার? আপনি খুব আকর্ষণীয় পদ্ধতির বর্ণনা। ধন্যবাদ। তবে আমি ওজেক্টিভ-সি বিকাশের একটি শিক্ষানবিশ। এবং আমার পক্ষে কিছু দিক বোঝা মুশকিল। হতে পারে আপনি গিটহাবের কিছু পরীক্ষা প্রকল্প আপলোড করতে পারেন এবং একটি লিঙ্ক দিতে পারেন?
ডেনিস

1
হ্যালো @ আলেকজান্ডারকারাবেরভ, আপনার দেওয়া স্টোরের ব্যাখ্যা সম্পর্কে আমি কিছুটা বিভ্রান্ত। ধরুন আমার কাছে 5 টি মডেল রয়েছে, প্রত্যেকের জন্য আমার কাছে 2 টি ক্লাস রয়েছে, এটি একটি নেটওয়ার্কিং এবং অবজেক্টের অন্যান্য ক্যাচিং বজায় রাখে। এখন আমার কাছে প্রতিটি মডেলের জন্য আলাদা স্টোর ক্লাস থাকা উচিত যা নেটওয়ার্কিং এবং ক্যাশে ক্লাসের ফাংশন কল করে বা একক স্টোর শ্রেণিতে প্রতিটি মডেলের জন্য সমস্ত ফাংশন রয়েছে, তাই নিয়ামক সর্বদা ডেটাগুলির জন্য একক ফাইল অ্যাক্সেস করে।
উল্লিখিত

1
@ আইকোডবাস্টার এই ডেমো প্রকল্পটি আমাকে এখানে বর্ণিত অনেকগুলি ধারণা বুঝতে সহায়তা করছে: github.com/darthpelo/

31

এই প্রশ্নের লক্ষ্য অনুসারে, আমি আমাদের আর্কিটেকচার পদ্ধতির বর্ণনা দিতে চাই।

আর্কিটেকচার পদ্ধতির

আমাদের সাধারণ আইওএস অ্যাপ্লিকেশনটির আর্কিটেকচারটি নিম্নলিখিত প্যাটার্নগুলির উপরে দাঁড়িয়েছে: পরিষেবা স্তর , এমভিভিএম , ইউআই ডেটা বন্ডিং , নির্ভরতা ইনজেকশন ; এবং কার্যকরী প্রতিক্রিয়াশীল প্রোগ্রামিং দৃষ্টান্ত।

আমরা নীচের যৌক্তিক স্তরগুলিতে একটি সাধারণ ভোক্তাদের মুখোমুখি অ্যাপ্লিকেশন টুকরো টুকরো করতে পারি:

  • সমাবেশ
  • মডেল
  • সেবা
  • সংগ্রহস্থল
  • পরিচালকের
  • coordinators
  • UI 'তে
  • অবকাঠামো

সমাবেশ স্তরটি আমাদের প্রয়োগের একটি বুটস্ট্র্যাপ পয়েন্ট। এটিতে ডিপেন্ডেন্সি ইনজেকশন ধারক এবং অ্যাপ্লিকেশনগুলির বস্তু এবং তাদের নির্ভরতাগুলির ঘোষণা contains এই স্তরটিতে অ্যাপ্লিকেশনটির কনফিগারেশন (ইউআরএল, তৃতীয় পক্ষের পরিষেবা কী এবং অন্যান্য) থাকতে পারে। এই উদ্দেশ্যে আমরা ব্যবহার করি টাইফুন লাইব্রেরি ।

মডেল স্তরে ডোমেন মডেলের ক্লাস, বৈধতা, ম্যাপিং রয়েছে। আমরা আমাদের মডেলগুলি ম্যাপিংয়ের জন্য ম্যান্টল লাইব্রেরি ব্যবহার করি: এটি সিরিয়ালাইজেশন / ডিজিটালাইজেশনটিকে JSONফর্ম্যাট এবং NSManagedObjectমডেলগুলিতে সমর্থন করে। আমাদের মডেলগুলির বৈধতা এবং ফর্ম উপস্থাপনার জন্য আমরা এফএক্সফর্ম এবং এফএক্সমোডেলভালিডেশন ব্যবহার করি লাইব্রেরি ।

পরিষেবাদির স্তরটি পরিষেবাগুলিকে ঘোষণা করে যা আমরা আমাদের ডোমেন মডেলটিতে প্রতিনিধিত্ব করা ডেটা প্রেরণ বা গ্রহণ করতে বাহ্যিক সিস্টেমের সাথে ইন্টারঅ্যাক্ট করার জন্য ব্যবহার করি। সুতরাং সাধারণত আমাদের সার্ভার এপিআই (প্রতিটি সত্তা), বার্তাপ্রেরণ পরিষেবা (যেমন পাবনব ), স্টোরেজ পরিষেবাদি (অ্যামাজন এস 3 এর মতো) ইত্যাদির সাথে যোগাযোগের জন্য পরিষেবা রয়েছে। মূলত পরিষেবাগুলি এসডিকে সরবরাহ করে (যেমন পাবনব এসডিকে) বা তাদের নিজস্ব যোগাযোগ বাস্তবায়ন করে যুক্তি। সাধারণ নেটওয়ার্কিংয়ের জন্য আমরা ব্যবহার করি এএফ নেট লাইব্রেরি করি

স্টোরেজ স্তরটির উদ্দেশ্য ডিভাইসে স্থানীয় ডেটা স্টোরেজ সংগঠিত করা। আমরা এর জন্য কোর ডেটা বা রাজ্য ব্যবহার করি (উভয় পক্ষেই ভাল এবং বুদ্ধি রয়েছে, কী ব্যবহার করবেন তা সিদ্ধান্ত কংক্রিটের চশমার উপর ভিত্তি করে)। কোর ডেটা সেটআপের জন্য আমরা এমডিএমকোরডাটা লাইব্রেরি এবং ক্লাসের গুচ্ছ - স্টোরেজগুলি (পরিষেবাদির সমান) ব্যবহার করি যা প্রতিটি সত্তার জন্য স্থানীয় স্টোরেজে অ্যাক্সেস সরবরাহ করে। রিয়েলমের জন্য আমরা কেবল স্থানীয় স্টোরেজে অ্যাক্সেস পেতে একই ধরণের স্টোরেজ ব্যবহার করি।

পরিচালকদের স্তর এমন এক স্থান যেখানে আমাদের বিমূর্ততা / মোড়ক থাকে।

পরিচালকের ভূমিকা হতে পারে:

  • এর বিভিন্ন বাস্তবায়নের সাথে শংসাপত্রগুলির পরিচালক (কীচেন, এনএসডিফাল্টস, ...)
  • বর্তমান সেশন ম্যানেজার যা বর্তমান ব্যবহারকারী সেশনটি কীভাবে রাখবে এবং সরবরাহ করতে পারে তা জানে
  • পাইপলাইন ক্যাপচার করুন যা মিডিয়া ডিভাইসগুলিতে অ্যাক্সেস সরবরাহ করে (ভিডিও রেকর্ডিং, অডিও, ছবি তোলা)
  • BLE ম্যানেজার যা ব্লুটুথ পরিষেবা এবং পেরিফেরিয়ালগুলিতে অ্যাক্সেস সরবরাহ করে
  • জিও লোকেশন ম্যানেজার
  • ...

সুতরাং, পরিচালকের ভূমিকায় কোনও বিষয় হতে পারে যা প্রয়োগের জন্য প্রয়োজনীয় কোনও নির্দিষ্ট দিক বা উদ্বেগের যুক্তি প্রয়োগ করে।

আমরা সিঙ্গলেটগুলি এড়ানোর চেষ্টা করি, তবে এই স্তরটি এমন একটি জায়গা যেখানে তারা প্রয়োজনে তারা বাস করে।

সমন্বয়কারী স্তর নির্দিষ্ট মডিউল (বৈশিষ্ট্য, পর্দা, ব্যবহারকারী গল্প বা ব্যবহারকারীর অভিজ্ঞতা) এর জন্য প্রয়োজনীয় কাজের এক অনুক্রমের সাথে তাদের যুক্তি যুক্ত করার জন্য অন্যান্য স্তর (পরিষেবা, স্টোরেজ, মডেল) থেকে প্রাপ্ত বস্তুর উপর নির্ভর করে এমন অবজেক্ট সরবরাহ করে। এটি সাধারণত অ্যাসিক্রোনাস অপারেশনগুলিকে শিকল দেয় এবং তাদের সাফল্য এবং ব্যর্থতার ক্ষেত্রে কীভাবে প্রতিক্রিয়া জানাতে হয় তা জানে। উদাহরণ হিসাবে আপনি কোনও বার্তা বৈশিষ্ট্য এবং সংশ্লিষ্ট MessagingCoordinatorঅবজেক্টটি কল্পনা করতে পারেন । বার্তা প্রেরণ পরিচালনা অপশন হ্যান্ডলিং এর মত হতে পারে:

  1. বৈধতা বার্তা (মডেল স্তর)
  2. স্থানীয়ভাবে বার্তা সংরক্ষণ করুন (বার্তাগুলি স্টোরেজ)
  3. বার্তা সংযুক্তি আপলোড করুন (অ্যামাজন এস 3 পরিষেবা)
  4. বার্তা স্থিতি এবং সংযুক্তি url আপডেট করুন এবং স্থানীয়ভাবে বার্তা সংরক্ষণ করুন (বার্তা সঞ্চয়স্থান)
  5. JSON ফর্ম্যাটে (মডেল স্তর) বার্তাটি সিরিয়াল করুন
  6. পাবনাব (পাবনাব পরিষেবা) তে বার্তা প্রকাশ করুন
  7. বার্তার স্থিতি এবং বৈশিষ্ট্যগুলি আপডেট করুন এবং এটি স্থানীয়ভাবে সংরক্ষণ করুন (বার্তাগুলি স্টোরেজ)

উপরের প্রতিটি পদক্ষেপে ত্রুটিটি যথাযথভাবে পরিচালনা করা হয়।

ইউআই স্তরতে নিম্নোক্ত সাবলেয়ারগুলি রয়েছে:

  1. ViewModels
  2. ViewControllers
  3. দেখেছে

ম্যাসিভ ভিউ কন্ট্রোলারগুলি এড়াতে আমরা এমভিভিএম প্যাটার্ন ব্যবহার করি এবং ভিউমোডেলগুলিতে ইউআই উপস্থাপনার জন্য প্রয়োজনীয় যুক্তি প্রয়োগ করি। একটি ভিউমোডেলে সাধারণত নির্ভরতা হিসাবে সমন্বয়কারী এবং পরিচালক থাকে। ভিউকন্ট্রোলার এবং কিছু ধরণের দর্শন (যেমন টেবিল দেখার ঘরগুলি) দ্বারা ব্যবহৃত ভিউমোডেলগুলি। ভিউকন্ট্রোলার এবং ভিউমোডেলগুলির মধ্যে আঠালো হ'ল ডেটা বাইন্ডিং এবং কমান্ড প্যাটার্ন। যাতে আঠালো থাকে তা সম্ভব করার জন্য আমরা ReactiveCocoa ব্যবহার করি লাইব্রেরি ।

আমরা রিঅ্যাকটিভ কোকো এবং এটি ব্যবহার করি RACSignal ধারণাটি একটি ইন্টারফেস হিসাবে এবং সমস্ত সমন্বয়কারী, পরিষেবাদি, সঞ্চয়স্থান পদ্ধতিগুলির রিটার্নিং মান ধরণের । এটি আমাদের ক্রিয়াকলাপ পরিচালনা করতে, সেগুলি সমান্তরালভাবে বা সিরিয়ালিভাবে চালাতে এবং রিঅ্যাকটিভ কোকোয়ার সরবরাহিত অন্যান্য অনেক দরকারী জিনিসকে মঞ্জুরি দেয়।

আমরা আমাদের ইউআই আচরণটি ঘোষণামূলক উপায়ে কার্যকর করার চেষ্টা করি। ডেটা বাইন্ডিং এবং অটো লেআউট এই লক্ষ্য অর্জনে অনেক সহায়তা করে।

অবকাঠামো স্তরে অ্যাপ্লিকেশন কাজের জন্য প্রয়োজনীয় সমস্ত সহায়ক, এক্সটেনশন, ইউটিলিটি রয়েছে।


এই পদ্ধতিরটি আমাদের এবং সেই ধরণের অ্যাপ্লিকেশনগুলির জন্য ভাল কাজ করে যা আমরা সাধারণত তৈরি করি। তবে আপনার বুঝতে হবে, এটি কংক্রিট দলের উদ্দেশ্য অনুসারে পরিবর্তন করা উচিত team

আশা করি এটা তোমাকে সাহায্য করবে!

এছাড়াও আপনি এই পরিষেবাটি হিসাবে আইওএস বিকাশ পোস্টে আইওএস বিকাশ প্রক্রিয়া সম্পর্কে আরও তথ্য পেতে পারেন


কয়েক মাস আগে এই আর্কিটেকচারটি পছন্দ করা শুরু হয়েছিল, অ্যালেক্সকে ভাগ করে নেওয়ার জন্য ধন্যবাদ! আমি অদূর ভবিষ্যতে RxSwift দিয়ে এটি চেষ্টা করতে চাই!
ইনগাহাম

18

সমস্ত আইওএস অ্যাপ্লিকেশন পৃথক হওয়ার কারণে, আমি মনে করি এখানে বিবেচনা করার জন্য বিভিন্ন পদ্ধতি রয়েছে, তবে আমি সাধারণত এই পথে চলে যাই:
সমস্ত এপিআই অনুরোধগুলি (সাধারণত নামযুক্ত এপিআইকোমিউনিকিটার) পরিচালনা করতে একটি কেন্দ্রীয় পরিচালক (সিঙ্গলটন) শ্রেণি তৈরি করুন এবং প্রতিটি উদাহরণ পদ্ধতিটি একটি এপিআই কল । এবং এখানে একটি কেন্দ্রীয় (অ-সর্বজনীন) পদ্ধতি রয়েছে:

-(RACSignal *)sendGetToServerToSubPath:(NSString *)path withParameters:(NSDictionary *)params;

রেকর্ডের জন্য, আমি 2 টি বড় লাইব্রেরি / ফ্রেমওয়ার্কগুলি, রিঅ্যাকটিভ কোকোয়া এবং এএফ নেটওয়ার্কিং ব্যবহার করি। রিঅ্যাকটিভ কোকো অ্যাসিঙ্ক নেটওয়ার্কিং প্রতিক্রিয়াগুলি পুরোপুরি পরিচালনা করে, আপনি এটি করতে পারেন (সেন্ড নেক্সট:, সেন্ডেরিয়র: ইত্যাদি)।
এই পদ্ধতিটি এপিআইকে কল করে, ফলাফল পেয়েছে এবং তাদেরকে 'কাঁচা' ফর্ম্যাটে আরএসি-র মাধ্যমে প্রেরণ করে (যেমন এনএসআর্রে কী এএফ নেট নেটওয়ার্কিং ফিরে আসে)।
তারপরে একটি পদ্ধতি getStuffList:যার মতো উপরের পদ্ধতিটি তার সিগন্যালের সাবস্ক্রাইব করে, কাঁচা তথ্যগুলিকে বস্তুগুলিতে পার্ট করে (মোটিসের মতো কিছু দিয়ে) এবং অবজেক্টগুলিকে একে একে কলারের কাছে প্রেরণ করে ( getStuffList:এবং অনুরূপ পদ্ধতিগুলি এমন সংকেতও ফেরত দেয় যা নিয়ামক সাবস্ক্রাইব করতে পারে )।
সাবস্ক্রাইব করা নিয়ন্ত্রক subscribeNext:ব্লক করে অবজেক্টগুলি গ্রহণ করে এবং তাদের পরিচালনা করে।

আমি বিভিন্ন অ্যাপ্লিকেশনে অনেক উপায়ে চেষ্টা করেছি তবে এইটি সবার মধ্যে সবচেয়ে ভাল কাজ করেছে তাই আমি সম্প্রতি কয়েকটি অ্যাপ্লিকেশনে এটি ব্যবহার করেছি এটি ছোট এবং বড় দুটি প্রকল্পেই ফিট করে এবং কোনও কিছু সংশোধন করার প্রয়োজন হলে এটি প্রসারিত এবং বজায় রাখা সহজ।
আশা করি এটি সাহায্য করবে, আমি আমার পদ্ধতির বিষয়ে অন্যের মতামত শুনতে চাই এবং অন্যেরা কীভাবে এটি সম্ভবত উন্নত হতে পারে বলে মনে করেন।


2
উত্তরের জন্য ধন্যবাদ +1। ভাল পদ্ধতির। আমি প্রশ্ন ছেড়ে দিই। হতে পারে আমরা অন্যান্য বিকাশকারীদের কাছ থেকে কিছু অন্য পদ্ধতির পেতে পারি।
মূলধারার

1
আমি এই পদ্ধতির ভিন্নতা পছন্দ করি - আমি একটি কেন্দ্রীয় এপিআই ম্যানেজার ব্যবহার করি যা এপিআইয়ের সাথে যোগাযোগের যান্ত্রিকতার যত্ন নেয়। তবে আমি আমার মডেল অবজেক্টগুলিতে সমস্ত কার্যকারিতা উন্মুক্ত করার চেষ্টা করি। মডেল মত পদ্ধতি প্রদান করবে + (void)getAllUsersWithSuccess:(void(^)(NSArray*))success failure:(void(^)(NSError*))failure;এবং - (void)postWithSuccess:(void(^)(instancetype))success failure:(void(^)(NSError*))failure;যা প্রয়োজনীয় প্রস্তুতি এবং তারপর এপিআই ব্যবস্থাপক মাধ্যমে কল করুন।
jsadler

1
এই পদ্ধতিটি সোজা, তবে এপিআইর সংখ্যা বাড়ার সাথে সাথে সিঙ্গলটন এপিআই ম্যানেজার বজায় রাখা আরও শক্ত হয়ে যায়। এবং প্রতিটি নতুন যুক্ত হওয়া এপিআই ম্যানেজারের সাথে সম্পর্কিত হবে, এই এপিআইটি কোন মডিউলটির অন্তর্ভুক্ত তা নয়। API অনুরোধগুলি পরিচালনা করতে github.com/kevin0571/STNetTaskQueue ব্যবহার করার চেষ্টা করুন ।
কেভিন

আপনি কেন আপনার লাইব্রেরিটির বিজ্ঞাপন দিচ্ছেন যা আমার সমাধান থেকে যতটা সম্ভব সম্ভব এবং আরও জটিল, আমি উল্লিখিত ছোট এবং বড় উভয় প্রকল্পে এই পদ্ধতির চেষ্টা করেছি এবং আমি একে ঠিক ব্যবহার করছি আমি যখন এই উত্তরটি লিখেছি তখন থেকেই একই। চতুর নামকরণের সম্মেলনগুলির সাথে এটি বজায় রাখা মোটেও কঠিন নয়।
রিকিয়ে

8

আমার পরিস্থিতিতে আমি সাধারণত রেসকিট ব্যবহার করি নেটওয়ার্ক স্তর সেট আপ করতে লাইব্রেরি । এটি সহজেই ব্যবহারযোগ্য পার্সিং সরবরাহ করে। এটি বিভিন্ন প্রতিক্রিয়া এবং স্টাফের জন্য ম্যাপিং সেটআপ করার ক্ষেত্রে আমার প্রচেষ্টা হ্রাস করে।

আমি স্বয়ংক্রিয়ভাবে ম্যাপিং সেটআপ করতে কিছু কোড যুক্ত করি। আমি আমার মডেলগুলির জন্য বেস ক্লাসটি সংজ্ঞায়িত করেছি (কোনও পদ্ধতি প্রয়োগ করা হয়েছে কিনা তা পরীক্ষা করার জন্য প্রচুর কোডের কারণে প্রোটোকল নয় এবং নিজেই মডেলগুলিতে কম কোড):

MappableEntry.h

@interface MappableEntity : NSObject

+ (NSArray*)pathPatterns;
+ (NSArray*)keyPathes;
+ (NSArray*)fieldsArrayForMapping;
+ (NSDictionary*)fieldsDictionaryForMapping;
+ (NSArray*)relationships;

@end

MappableEntry.m

@implementation MappableEntity

+(NSArray*)pathPatterns {
    return @[];
}

+(NSArray*)keyPathes {
    return nil;
}

+(NSArray*)fieldsArrayForMapping {
    return @[];
}

+(NSDictionary*)fieldsDictionaryForMapping {
    return @{};
}

+(NSArray*)relationships {
    return @[];
}

@end

সম্পর্কগুলি এমন বস্তু যা প্রতিক্রিয়া হিসাবে নেস্টেড বস্তুর প্রতিনিধিত্ব করে:

RelationshipObject.h

@interface RelationshipObject : NSObject

@property (nonatomic,copy) NSString* source;
@property (nonatomic,copy) NSString* destination;
@property (nonatomic) Class mappingClass;

+(RelationshipObject*)relationshipWithKey:(NSString*)key andMappingClass:(Class)mappingClass;
+(RelationshipObject*)relationshipWithSource:(NSString*)source destination:(NSString*)destination andMappingClass:(Class)mappingClass;

@end

RelationshipObject.m

@implementation RelationshipObject

+(RelationshipObject*)relationshipWithKey:(NSString*)key andMappingClass:(Class)mappingClass {
    RelationshipObject* object = [[RelationshipObject alloc] init];
    object.source = key;
    object.destination = key;
    object.mappingClass = mappingClass;
    return object;
}

+(RelationshipObject*)relationshipWithSource:(NSString*)source destination:(NSString*)destination andMappingClass:(Class)mappingClass {
    RelationshipObject* object = [[RelationshipObject alloc] init];
    object.source = source;
    object.destination = destination;
    object.mappingClass = mappingClass;
    return object;
}

@end

তারপরে আমি রেস্টকিটের জন্য এইভাবে ম্যাপিং সেটআপ করছি:

ObjectMappingInitializer.h

@interface ObjectMappingInitializer : NSObject

+(void)initializeRKObjectManagerMapping:(RKObjectManager*)objectManager;

@end

ObjectMappingInitializer.m

@interface ObjectMappingInitializer (Private)

+ (NSArray*)mappableClasses;

@end

@implementation ObjectMappingInitializer

+(void)initializeRKObjectManagerMapping:(RKObjectManager*)objectManager {

    NSMutableDictionary *mappingObjects = [NSMutableDictionary dictionary];

    // Creating mappings for classes
    for (Class mappableClass in [self mappableClasses]) {
        RKObjectMapping *newMapping = [RKObjectMapping mappingForClass:mappableClass];
        [newMapping addAttributeMappingsFromArray:[mappableClass fieldsArrayForMapping]];
        [newMapping addAttributeMappingsFromDictionary:[mappableClass fieldsDictionaryForMapping]];
        [mappingObjects setObject:newMapping forKey:[mappableClass description]];
    }

    // Creating relations for mappings
    for (Class mappableClass in [self mappableClasses]) {
        RKObjectMapping *mapping = [mappingObjects objectForKey:[mappableClass description]];
        for (RelationshipObject *relation in [mappableClass relationships]) {
            [mapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:relation.source toKeyPath:relation.destination withMapping:[mappingObjects objectForKey:[relation.mappingClass description]]]];
        }
    }

    // Creating response descriptors with mappings
    for (Class mappableClass in [self mappableClasses]) {
        for (NSString* pathPattern in [mappableClass pathPatterns]) {
            if ([mappableClass keyPathes]) {
                for (NSString* keyPath in [mappableClass keyPathes]) {
                    [objectManager addResponseDescriptor:[RKResponseDescriptor responseDescriptorWithMapping:[mappingObjects objectForKey:[mappableClass description]] method:RKRequestMethodAny pathPattern:pathPattern keyPath:keyPath statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]];
                }
            } else {
                [objectManager addResponseDescriptor:[RKResponseDescriptor responseDescriptorWithMapping:[mappingObjects objectForKey:[mappableClass description]] method:RKRequestMethodAny pathPattern:pathPattern keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]];
            }
        }
    }

    // Error Mapping
    RKObjectMapping *errorMapping = [RKObjectMapping mappingForClass:[Error class]];
    [errorMapping addAttributeMappingsFromArray:[Error fieldsArrayForMapping]];
    for (NSString *pathPattern in Error.pathPatterns) {
        [[RKObjectManager sharedManager] addResponseDescriptor:[RKResponseDescriptor responseDescriptorWithMapping:errorMapping method:RKRequestMethodAny pathPattern:pathPattern keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassClientError)]];
    }
}

@end

@implementation ObjectMappingInitializer (Private)

+ (NSArray*)mappableClasses {
    return @[
        [FruiosPaginationResults class],
        [FruioItem class],
        [Pagination class],
        [ContactInfo class],
        [Credentials class],
        [User class]
    ];
}

@end

ম্যাপেবল এন্ট্রি বাস্তবায়নের কয়েকটি উদাহরণ:

User.h

@interface User : MappableEntity

@property (nonatomic) long userId;
@property (nonatomic, copy) NSString *username;
@property (nonatomic, copy) NSString *email;
@property (nonatomic, copy) NSString *password;
@property (nonatomic, copy) NSString *token;

- (instancetype)initWithUsername:(NSString*)username email:(NSString*)email password:(NSString*)password;

- (NSDictionary*)registrationData;

@end

User.m

@implementation User

- (instancetype)initWithUsername:(NSString*)username email:(NSString*)email password:(NSString*)password {
    if (self = [super init]) {
        self.username = username;
        self.email = email;
        self.password = password;
    }
    return self;
}

- (NSDictionary*)registrationData {
    return @{
        @"username": self.username,
        @"email": self.email,
        @"password": self.password
    };
}

+ (NSArray*)pathPatterns {
    return @[
        [NSString stringWithFormat:@"/api/%@/users/register", APIVersionString],
        [NSString stringWithFormat:@"/api/%@/users/login", APIVersionString]
    ];
}

+ (NSArray*)fieldsArrayForMapping {
    return @[ @"username", @"email", @"password", @"token" ];
}

+ (NSDictionary*)fieldsDictionaryForMapping {
    return @{ @"id": @"userId" };
}

@end

অনুরোধ মোড়ানো সম্পর্কে এখন:

সমস্ত APIRequest ক্লাসে লাইনের দৈর্ঘ্য হ্রাস করতে আমার কাছে ব্লক সংজ্ঞা সহ শিরোনাম ফাইলটি রয়েছে:

APICallbacks.h

typedef void(^SuccessCallback)();
typedef void(^SuccessCallbackWithObjects)(NSArray *objects);
typedef void(^ErrorCallback)(NSError *error);
typedef void(^ProgressBlock)(float progress);

এবং আমার এপিআইরকোয়েস্ট শ্রেণীর উদাহরণ যা আমি ব্যবহার করছি:

LoginAPI.h

@interface LoginAPI : NSObject

- (void)loginWithCredentials:(Credentials*)credentials onSuccess:(SuccessCallbackWithObjects)onSuccess onError:(ErrorCallback)onError;

@end

LoginAPI.m

@implementation LoginAPI

- (void)loginWithCredentials:(Credentials*)credentials onSuccess:(SuccessCallbackWithObjects)onSuccess onError:(ErrorCallback)onError {
    [[RKObjectManager sharedManager] postObject:nil path:[NSString stringWithFormat:@"/api/%@/users/login", APIVersionString] parameters:[credentials credentialsData] success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
        onSuccess(mappingResult.array);
    } failure:^(RKObjectRequestOperation *operation, NSError *error) {
        onError(error);
    }];
}

@end

এবং কোডগুলিতে আপনাকে যা করতে হবে, কেবল এপিআই অবজেক্টটি আরম্ভ করুন এবং যখনই আপনার এটি প্রয়োজন হবে:

SomeViewController.m

@implementation SomeViewController {
    LoginAPI *_loginAPI;
    // ...
}

- (void)viewDidLoad {
    [super viewDidLoad];

    _loginAPI = [[LoginAPI alloc] init];
    // ...
}

// ...

- (IBAction)signIn:(id)sender {
    [_loginAPI loginWithCredentials:_credentials onSuccess:^(NSArray *objects) {
        // Success Block
    } onError:^(NSError *error) {
        // Error Block
    }];
}

// ...

@end

আমার কোডটি নিখুঁত নয়, তবে একবার সেট করা এবং বিভিন্ন প্রকল্পের জন্য ব্যবহার করা সহজ। এটি যদি কারও কাছে আকর্ষণীয় হয় তবে এমবি আমি কিছুটা সময় ব্যয় করতে এবং গিটহাব এবং কোকোপোডে কোথাও এর জন্য সর্বজনীন সমাধান করতে পারি।


7

আমার মনে সমস্ত সফ্টওয়্যার আর্কিটেকচার প্রয়োজনের দ্বারা চালিত। এটি যদি শেখার বা ব্যক্তিগত উদ্দেশ্যে হয়, তবে প্রাথমিক লক্ষ্যটি নির্ধারণ করুন এবং সেই ড্রাইভটি আর্কিটেকচারটি রাখুন। এটি যদি ভাড়ার কাজ হয় তবে ব্যবসায়ের প্রয়োজনীয়তা সর্বজনীন। কৌশলটি হ'ল চকচকে জিনিসগুলি আপনাকে আসল প্রয়োজনীয়তা থেকে দূরে না ফেলে। আমি এটি করা কঠিন মনে করি। এই ব্যবসায়টিতে সর্বদা নতুন চকচকে জিনিস উপস্থিত হয় এবং সেগুলির অনেকগুলি কার্যকর হয় না তবে আপনি সর্বদা এটি সামনে বলতে পারবেন না। প্রয়োজনের দিকে মনোনিবেশ করুন এবং আপনি যদি পারেন তবে খারাপ পছন্দগুলি ত্যাগ করতে রাজি হন।

উদাহরণস্বরূপ, আমি সম্প্রতি একটি স্থানীয় ব্যবসায়ের জন্য একটি ফটো ভাগ করে নেওয়ার অ্যাপ্লিকেশনটির দ্রুত প্রোটোটাইপ করেছি। যেহেতু ব্যবসায়ের প্রয়োজন ছিল দ্রুত এবং নোংরা কিছু করা, তাই আর্কিটেকচারটি ক্যামেরার পপআপ করার জন্য কিছু আইওএস কোড এবং একটি সেন্ড বোতামের সাথে সংযুক্ত কিছু নেটওয়ার্ক কোড যা এস 3 স্টোরটিতে ছবিটি আপলোড করে এবং একটি সিম্পলডিবি ডোমেনে লিখেছিল ended কোডটি ছিল তুচ্ছ এবং ব্যয় ন্যূনতম এবং ক্লায়েন্টের একটি স্কেজেবল ফটো সংগ্রহ ওয়েবে আরএসটি কল সহ অ্যাক্সেসযোগ্য। সস্তা এবং বোবা, অ্যাপটিতে প্রচুর ত্রুটি ছিল এবং উপলক্ষে ইউআই লক করে দেওয়া হবে তবে এটি প্রোটোটাইপের জন্য আরও কিছু করা বর্জ্য হবে এবং এটি তাদের কর্মীদের কাছে স্থাপন করতে এবং পারফরম্যান্স বা স্কেলাবিলিটি ছাড়াই সহজেই হাজার হাজার পরীক্ষার চিত্র উত্পন্ন করতে দেয় উদ্বেগ। ক্রেপি আর্কিটেকচার, তবে এটি প্রয়োজনীয়তার সাথে পুরোপুরি খাপ খায়।

অন্য একটি প্রকল্পে স্থানীয় সুরক্ষিত ডাটাবেস বাস্তবায়নের সাথে জড়িত যা নেটওয়ার্ক উপলব্ধ থাকলে পটভূমিতে সংস্থা সিস্টেমের সাথে সিঙ্ক্রোনাইজ হয় izes আমি একটি ব্যাকগ্রাউন্ড সিঙ্ক্রোনাইজার তৈরি করেছি যা रेस्टকিটটি ব্যবহার করে বলে মনে হয়েছিল যে আমার প্রয়োজনীয় সমস্ত কিছুই আছে। তবে আইডিসিঙ্ক্র্যাটিক জেএসওন মোকাবেলার জন্য আমাকে রেস্টকিটের জন্য এতগুলি কাস্টম কোড লিখতে হয়েছিল যে আমি কোরেডাটা ট্রান্সফর্মেশনগুলিতে নিজের জেএসওএন লিখে এটি আরও দ্রুত করতে পারতাম। তবে গ্রাহক এই অ্যাপটি ঘরে আনতে চেয়েছিলেন এবং আমি অনুভব করেছি যে রেস্টকিট তারা অন্য প্ল্যাটফর্মগুলিতে ব্যবহৃত ফ্রেমওয়ার্কগুলির অনুরূপ হবে। আমি অপেক্ষা করছি যে এটি একটি ভাল সিদ্ধান্ত ছিল কিনা।

আবার আমার কাছে বিষয়টি হ'ল প্রয়োজনের দিকে মনোনিবেশ করা এবং এটি আর্কিটেকচারটি নির্ধারণ করা উচিত। তৃতীয় পক্ষের প্যাকেজগুলি ব্যবহার এড়াতে আমি জাহান্নামের মতো চেষ্টা করি কারণ তারা ব্যয় নিয়ে আসে যা অ্যাপটি কিছুক্ষন মাঠে থাকার পরে উপস্থিত হয়। ক্লাসের শ্রেণিবদ্ধতাগুলি এড়াতে চেষ্টা করব কারণ তারা খুব কমই বেতন দেয়। আমি যদি পুরোপুরি ফিট না করে এমন প্যাকেজ গ্রহণের পরিবর্তে যুক্তিসঙ্গত সময়ে কিছু লিখতে পারি, তবে আমি এটি করি it আমার কোডটি ডিবাগিংয়ের জন্য সুগঠিত এবং যথাযথভাবে মন্তব্য করা হয়েছে তবে তৃতীয় পক্ষের প্যাকেজগুলি খুব কমই হয়। এই বলে যে, আমি এএফ নেটওয়ার্কিং উপেক্ষা এবং ভাল কাঠামোগত, ভাল মন্তব্য, এবং বজায় রাখতে খুব দরকারী মনে করি এবং আমি এটি প্রচুর ব্যবহার করি! রেস্টকিট অনেকগুলি সাধারণ কেস কভার করে তবে আমার মনে হয় আমি যখন এটি ব্যবহার করি তখন আমার লড়াই হয়েছিল, এবং আমি যে ডেটা উত্সগুলির মুখোমুখি হই তাদের বেশিরভাগই কিরক এবং সমস্যাগুলি পূর্ণ যা কাস্টম কোড সহ সেরাভাবে পরিচালনা করা হয়। আমার শেষ কয়েকটি অ্যাপ্লিকেশনগুলিতে আমি জেএসএন রূপান্তরকারীগুলিতে কেবল ব্যবহার করি এবং কয়েকটি ইউটিলিটি পদ্ধতি লিখি।

আমি সর্বদা একটি প্যাটার্নটি ব্যবহার করি সেটি হল মূল থ্রেডটি থেকে নেটওয়ার্ক কল করা off সর্বশেষ 4-5 টি অ্যাপ্লিকেশনগুলি আমি প্রায়শই জাগ্রত করে এবং প্রয়োজন অনুসারে নেটওয়ার্ক কার্য সম্পাদন করে ডিসপ্যাচ_সোর্স_ক্রিয়েট ব্যবহার করে একটি পটভূমি টাইমার টাস্ক সেট আপ করে। আপনাকে কিছু থ্রেড সুরক্ষা কাজ করতে হবে এবং নিশ্চিত হওয়া উচিত যে ইউআই সংশোধনকারী কোডটি মূল থ্রেডে প্রেরণ হয়েছে। এটি আপনার অনবোর্ডিং / আরম্ভকরণটি এমনভাবে করতে সহায়তা করে যাতে ব্যবহারকারী বোঝা বা দেরি না করে। এখনও পর্যন্ত এটি বরং ভাল কাজ করে চলেছে। আমি এই জিনিসগুলি সন্ধানের পরামর্শ দিই।

পরিশেষে, আমি মনে করি যে আমরা যেমন আরও বেশি কাজ করি এবং ওএস যেমন বিকশিত হয় ততই আমরা আরও ভাল সমাধান বিকাশের প্রবণতা অর্জন করি। অন্যান্য লোকেরা যে বাধ্যতামূলক বলে দাবি করে আমাকে যে নকশাগুলি এবং নকশাগুলি অনুসরণ করতে হবে তা বিশ্বাস করতে পেরে আমাকে কয়েক বছর সময় লেগেছে। যদি আমি এমন একটি প্রসঙ্গে কাজ করছি যেখানে এটি স্থানীয় ধর্মের অঙ্গ, আহেম, আমি বিভাগীয় সেরা ইঞ্জিনিয়ারিং অনুশীলনগুলি বোঝাচ্ছি, তবে আমি চিঠির রীতিনীতি অনুসরণ করি, এটাই তারা আমাকে প্রদান করছে। তবে আমি খুব কমই খুঁজে পাই যে পুরানো ডিজাইনগুলি এবং নিদর্শনগুলি অনুসরণ করা অনুকূল সমাধান is আমি সর্বদা ব্যবসায়ের প্রয়োজনীয় প্রিজমটির মাধ্যমে সমাধানটি দেখার চেষ্টা করি এবং এটির সাথে মিলে যাওয়ার জন্য আর্কিটেকচারটি তৈরি করি এবং জিনিসগুলি যতটা সম্ভব সহজ রাখা যায়। যখন আমার মনে হয় সেখানে পর্যাপ্ত পরিমাণ নেই, তবে সবকিছু সঠিকভাবে কাজ করে, তখন আমি সঠিক পথে আছি।


4

আমি যে পদ্ধতিটি এখান থেকে পেয়েছি তা ব্যবহার করি: https://github.com/Constantine-Fry/Foursquare-API-v2 । আমি সেই লাইব্রেরিটি সুইফটে আবার লিখেছি এবং আপনি কোডের এই অংশগুলি থেকে স্থাপত্য পদ্ধতি দেখতে পাচ্ছেন:

typealias OpertaionCallback = (success: Bool, result: AnyObject?) -> ()

class Foursquare{
    var authorizationCallback: OperationCallback?
    var operationQueue: NSOperationQueue
    var callbackQueue: dispatch_queue_t?

    init(){
        operationQueue = NSOperationQueue()
        operationQueue.maxConcurrentOperationCount = 7;
        callbackQueue = dispatch_get_main_queue();
    }

    func checkIn(venueID: String, shout: String, callback: OperationCallback) -> NSOperation {
        let parameters: Dictionary <String, String> = [
            "venueId":venueID,
            "shout":shout,
            "broadcast":"public"]
        return self.sendRequest("checkins/add", parameters: parameters, httpMethod: "POST", callback: callback)
    }

    func sendRequest(path: String, parameters: Dictionary <String, String>, httpMethod: String, callback:OperationCallback) -> NSOperation{
        let url = self.constructURL(path, parameters: parameters)
        var request = NSMutableURLRequest(URL: url)
        request.HTTPMethod = httpMethod
        let operation = Operation(request: request, callbackBlock: callback, callbackQueue: self.callbackQueue!)
        self.operationQueue.addOperation(operation)
        return operation
    }

    func constructURL(path: String, parameters: Dictionary <String, String>) -> NSURL {
        var parametersString = kFSBaseURL+path
        var firstItem = true
        for key in parameters.keys {
            let string = parameters[key]
            let mark = (firstItem ? "?" : "&")
            parametersString += "\(mark)\(key)=\(string)"
            firstItem = false
        }
    return NSURL(string: parametersString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding))
    }
}

class Operation: NSOperation {
    var callbackBlock: OpertaionCallback
    var request: NSURLRequest
    var callbackQueue: dispatch_queue_t

    init(request: NSURLRequest, callbackBlock: OpertaionCallback, callbackQueue: dispatch_queue_t) {
        self.request = request
        self.callbackBlock = callbackBlock
        self.callbackQueue = callbackQueue
    }

    override func main() {
        var error: NSError?
        var result: AnyObject?
        var response: NSURLResponse?

        var recievedData: NSData? = NSURLConnection.sendSynchronousRequest(self.request, returningResponse: &response, error: &error)

        if self.cancelled {return}

        if recievedData{
            result = NSJSONSerialization.JSONObjectWithData(recievedData, options: nil, error: &error)
            if result != nil {
                if result!.isKindOfClass(NSClassFromString("NSError")){
                    error = result as? NSError
            }
        }

        if self.cancelled {return}

        dispatch_async(self.callbackQueue, {
            if (error) {
                self.callbackBlock(success: false, result: error!);
            } else {
                self.callbackBlock(success: true, result: result!);
            }
            })
    }

    override var concurrent:Bool {get {return true}}
}

মূলত, NSOperation সাবক্লাস রয়েছে যা NSURLRequest করে, JSON প্রতিক্রিয়া পার্স করে এবং ফলাফলের সাথে ক্যুব্যাক ব্লকে কাতারে যুক্ত করে। প্রধান এপিআই ক্লাসটি এনএসআরএল অনুরোধ তৈরি করে, এনএসওরেশন সাবক্লাসটি আরম্ভ করে এবং এটি কাতারে যুক্ত করে।


3

আমরা পরিস্থিতির উপর নির্ভর করে কয়েকটি পন্থা ব্যবহার করি। বেশিরভাগ জিনিসের জন্য এএফ নেটর্কেটিং হ'ল সহজ এবং সবচেয়ে দৃ approach় পদ্ধতির মধ্যে আপনি শিরোনাম সেট করতে পারেন, মাল্টিপার্ট ডেটা আপলোড করতে পারেন, জিইটি, পোষ্ট, পুট এবং ডিলেট করতে পারেন এবং ইউআইকিট-র জন্য আরও কিছু অতিরিক্ত বিভাগ রয়েছে যা আপনাকে উদাহরণস্বরূপ একটি চিত্র সেট করতে দেয় একটি ইউআরএল। অনেকগুলি কল সহ একটি জটিল অ্যাপ্লিকেশনটিতে আমরা মাঝে মাঝে এটিকে আমাদের নিজস্ব কোনও সুবিধামত পদ্ধতিতে বিমূর্ত করি যা এমন কিছু হবে:

-(void)makeRequestToUrl:(NSURL *)url withParameters:(NSDictionary *)parameters success:(void (^)(id responseObject))success failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure;

কয়েকটি পরিস্থিতি রয়েছে যেখানে এএফ নেটওয়ার্কিং যথাযথ নয় যেমন আপনি যেখানে ফ্রেমওয়ার্ক বা অন্যান্য লাইব্রেরির উপাদান তৈরি করছেন যেমন এএফ নেটওয়ার্কিং ইতিমধ্যে অন্য কোড বেসে থাকতে পারে। আপনি যদি কোনও একক কল করছেন বা কোনও অনুরোধ / প্রতিক্রিয়া শ্রেণিতে বিমুক্ত হয়ে থাকেন তবে এই পরিস্থিতিতে আপনি একটি এনএস পরিবর্তনশীল URL অনুরোধটি ইনলাইন ব্যবহার করবেন।


আমার জন্য এটি সেরা এবং স্পষ্ট উত্তর, চিয়ার্স। "এটি যে সহজ"। @ মার্টিন, ব্যক্তিগতভাবে আমরা কেবলমাত্র NSMutable URL অনুসন্ধান সর্বদা ব্যবহার করি; এএফ নেটওয়ার্কিং ব্যবহারের কোন বাস্তব কারণ আছে?
ফ্যাটি

এএফ নেটওয়ার্কিং সত্যিই সুবিধাজনক। আমার পক্ষে সাফল্য এবং ব্যর্থ ব্লকগুলি যথাযথভাবে তৈরি করে দেয় কারণ কোডটি পরিচালনা করা সহজ হয়। আমি সম্মত হই যে এটি মোটামুটি ওভারকিল কখনও কখনও যদিও।
মার্টিন

ব্লকগুলিতে একটি দুর্দান্ত পয়েন্ট, এর জন্য ধন্যবাদ। আমার ধারণা, এর সুনির্দিষ্ট প্রকৃতিটি সমস্ত সুইফটের সাথে পরিবর্তিত হবে।
ফ্যাটি

2

আমার অ্যাপ্লিকেশনগুলি ডিজাইন করার সময় আমি সিলেটলেটগুলি এড়িয়ে চলি। এগুলি অনেক লোকের কাছে যেতে সাধারণ go তবে আমি মনে করি আপনি অন্য কোথাও আরও মার্জিত সমাধান পেতে পারেন। সাধারণত আমি যা করি তা হ'ল কোরডাটাতে আমার সত্তা তৈরি করা এবং তারপরে আমার আরএসটি কোডটি এনএসম্যানেজডঅবজেক্ট বিভাগে রাখা। উদাহরণস্বরূপ যদি আমি একটি নতুন ব্যবহারকারী তৈরি করতে এবং পোস্ট করতে চাইতাম তবে আমি এটি করতাম:

User* newUser = [User createInManagedObjectContext:managedObjectContext];
[newUser postOnSuccess:^(...) { ... } onFailure:^(...) { ... }];

আমি অবজেক্ট ম্যাপিংয়ের জন্য RESTKit ব্যবহার করি এবং এটি শুরুতে শুরু করি। আমি আপনার সমস্ত কলকে একটি সিংগেলনের মাধ্যমে সময় নষ্ট হতে রাউটিং করে এবং প্রচুর বয়লারপ্লেট যুক্ত করে যা প্রয়োজন হয় না।

এনএসম্যানেজডঅবজেক্ট + এক্সটেনশনগুলি.এম তে:

+ (instancetype)createInContext:(NSManagedObjectContext*)context
{
    NSAssert(context.persistentStoreCoordinator.managedObjectModel.entitiesByName[[self entityName]] != nil, @"Entity with name %@ not found in model. Is your class name the same as your entity name?", [self entityName]);
    return [NSEntityDescription insertNewObjectForEntityForName:[self entityName] inManagedObjectContext:context];
}

এনএসম্যানেজডঅবজেক্ট + নেটওয়ার্কিং.এম এ:

- (void)getOnSuccess:(RESTSuccess)onSuccess onFailure:(RESTFailure)onFailure blockInput:(BOOL)blockInput
{
    [[RKObjectManager sharedManager] getObject:self path:nil parameters:nil success:onSuccess failure:onFailure];
    [self handleInputBlocking:blockInput];
}

আপনি বিভাগগুলির মাধ্যমে একটি সাধারণ বেস শ্রেণীর কার্যকারিতা বাড়িয়ে দিতে পারলে অতিরিক্ত সহায়ক শ্রেণি কেন যুক্ত করবেন?

আপনি যদি আমার সমাধান সম্পর্কে আরও বিস্তারিত তথ্যে আগ্রহী হন তবে আমাকে জানান। আমি ভাগ করে নিচ্ছি


3
অবশ্যই একটি ব্লগ পোস্টে আরও বিস্তারিত এই পদ্ধতির সম্পর্কে পড়তে আগ্রহী হবে।
দানিয়াল আয়তেকিন

0

ব্যবহার করে দেখুন https://github.com/kevin0571/STNetTaskQueue

পৃথক ক্লাসে এপিআই অনুরোধ তৈরি করুন।

STNetTaskQueue থ্রেডিং এবং ডেলিগেট / কলব্যাক মোকাবেলা করবে।

বিভিন্ন প্রোটোকলের জন্য বর্ধমান।


0

খাঁটি শ্রেণির নকশার দৃষ্টিকোণ থেকে আপনার কাছে সাধারণত এমন কিছু থাকবে:

  • আপনার ভিউ নিয়ন্ত্রণকারীরা এক বা একাধিক মতামত নিয়ন্ত্রণ করছে
  • ডেটা মডেল শ্রেণি - আপনি প্রকৃত স্বতন্ত্র সত্তা কতটা বাস্তবের উপর নির্ভরশীল তা নির্ভর করে এবং কীভাবে তারা সম্পর্কিত।

    উদাহরণস্বরূপ, যদি আপনার চারটি আলাদা উপস্থাপনায় (তালিকা, চার্ট, গ্রাফ ইত্যাদি) প্রদর্শিত আইটেমগুলির একটি অ্যারে থাকে তবে আপনার আইটেমের তালিকার জন্য একটি ডেটা মডেল ক্লাস থাকবে, একটি আইটেমের জন্য আরও একটি। আইটেমটি ক্লাসের তালিকা একটি ট্যাব বার নিয়ামক বা এনএভি নিয়ন্ত্রকের সব শিশুদের - চার দৃশ্য কনট্রোলার দ্বারা ভাগ করা হবে।

    ডেটা মডেল ক্লাসগুলি কেবলমাত্র ডেটা প্রদর্শন করার ক্ষেত্রেই কার্যকর হবে না, সেগুলি সিরিয়ালাইজ করার ক্ষেত্রেও প্রত্যেকে জেএসওএন / এক্সএমএল / সিএসভি (বা অন্য কোনও কিছু) রফতানি পদ্ধতির মাধ্যমে তাদের নিজস্ব সিরিয়ালাইজেশন বিন্যাসটি প্রকাশ করতে পারে।

  • এটি বোঝার জন্য গুরুত্বপূর্ণ যে আপনার এপিআই অনুরোধ বিল্ডার ক্লাসগুলিরও দরকার যা আপনার আরএসপি এপিআই সমাপ্তির সাথে সরাসরি ম্যাপ করে। ধরা যাক আপনার এমন একটি এপিআই রয়েছে যা ব্যবহারকারীকে লগ ইন করে - তাই আপনার লগইন এপিআই বিল্ডার শ্রেণি লগইন এপিআইয়ের জন্য পোস্ট জেএসএন পেডলোড তৈরি করবে। অন্য একটি উদাহরণে, ক্যাটালগ আইটেমগুলির তালিকার জন্য একটি এপিআই অনুরোধ বিল্ডার শ্রেণি এপিআই সম্পর্কিত জিইটি কোয়েরি স্ট্রিং তৈরি করবে এবং বিশ্রামের জিইটি কোয়েরি সরিয়ে দেবে।

    এই এপিআই অনুরোধ বিল্ডার ক্লাসগুলি সাধারণত দেখা নিয়ন্ত্রকদের কাছ থেকে ডেটা গ্রহণ করবে এবং একই তথ্যটি ইউআই আপডেট / অন্যান্য ক্রিয়াকলাপগুলির জন্য নিয়ামকগুলি দেখতে ফিরে যাবে। তারপরে দেখুন নিয়ন্ত্রকরা কীভাবে সেই ডেটা দিয়ে ডেটা মডেল অবজেক্টগুলি আপডেট করবেন decide

  • অবশেষে, REST ক্লায়েন্টের হৃদয় - আপনার অ্যাপ্লিকেশনটি যে সকল প্রকারের API অনুরোধ করে তার জন্য বিস্মৃত এপিআই ডেটা ফ্যাচার ক্লাস । এই শ্রেণিটি সম্ভবত একটি সিঙ্গলটন হবে, তবে অন্যরা যেমন উল্লেখ করেছে, এটি সিঙ্গলটন হতে হবে না।

    নোট করুন যে লিঙ্কটি কেবলমাত্র একটি সাধারণ বাস্তবায়ন এবং অধিবেশন, কুকিজ ইত্যাদির মতো পরিস্থিতিতে বিবেচনা করে না, তবে কোনও তৃতীয় পক্ষের ফ্রেমওয়ার্ক ব্যবহার না করেই আপনাকে চালিত করা যথেষ্ট।


0

এই প্রশ্নের ইতিমধ্যে অনেকগুলি দুর্দান্ত এবং বিস্তৃত উত্তর রয়েছে, তবে আমি অনুভব করি যেহেতু অন্য কারও কাছে নেই বলেই আমি এটি উল্লেখ করতে হবে।

সুইফ্টের জন্য অ্যালামোফায়ার। https://github.com/Alamofire/Alamofire

এটি এএফ নেটওয়ার্কিং হিসাবে একই ব্যক্তিদের দ্বারা তৈরি করা হয়েছে, তবে সুইফটকে সামনে রেখে আরও সরাসরি নকশাকৃত।


0

আমার মনে হয় আপাতত মাঝারি প্রকল্পের ব্যবহার এমভিভিএম আর্কিটেকচার এবং বড় প্রকল্পগুলি ভিআইপিআর আর্কিটেকচার ব্যবহার করে এবং অর্জনের চেষ্টা করবে

  • প্রোটোকল ওরিয়েন্টেড প্রোগ্রামিং
  • সফ্টওয়্যার নকশা নিদর্শন
  • বিক্রয় নীতি
  • জেনেরিক প্রোগ্রামিং
  • নিজেকে পুনরাবৃত্তি করবেন না (DRY)

এবং আইওএস নেটওয়ার্কিং অ্যাপ্লিকেশন তৈরির জন্য আর্কিটেকচারাল পন্থাগুলি (আরএসটি ক্লায়েন্ট)

পরিষ্কার এবং পঠনযোগ্য কোডের জন্য পৃথকীকরণ উদ্বেগ সদৃশ এড়ানো:

import Foundation
enum DataResponseError: Error {
    case network
    case decoding

    var reason: String {
        switch self {
        case .network:
            return "An error occurred while fetching data"
        case .decoding:
            return "An error occurred while decoding data"
        }
    }
}

extension HTTPURLResponse {
    var hasSuccessStatusCode: Bool {
        return 200...299 ~= statusCode
    }
}

enum Result<T, U: Error> {
    case success(T)
    case failure(U)
}

নির্ভরতা বিপর্যয়

 protocol NHDataProvider {
        func fetchRemote<Model: Codable>(_ val: Model.Type, url: URL, completion: @escaping (Result<Codable, DataResponseError>) -> Void)
    }

প্রধান দায়বদ্ধ:

  final class NHClientHTTPNetworking : NHDataProvider {

        let session: URLSession

        init(session: URLSession = URLSession.shared) {
            self.session = session
        }

        func fetchRemote<Model: Codable>(_ val: Model.Type, url: URL,
                             completion: @escaping (Result<Codable, DataResponseError>) -> Void) {
            let urlRequest = URLRequest(url: url)
            session.dataTask(with: urlRequest, completionHandler: { data, response, error in
                guard
                    let httpResponse = response as? HTTPURLResponse,
                    httpResponse.hasSuccessStatusCode,
                    let data = data
                    else {
                        completion(Result.failure(DataResponseError.network))
                        return
                }
                guard let decodedResponse = try? JSONDecoder().decode(Model.self, from: data) else {
                    completion(Result.failure(DataResponseError.decoding))
                    return
                }
                completion(Result.success(decodedResponse))
            }).resume()
        }
    }

আপনি এখানে পাবেন গিটিহাব এমভিভিএম আর্কিটেকচার বিশ্রাম এপিআই সুইফট প্রকল্পের সাথে


0

মোবাইল সফ্টওয়্যার ইঞ্জিনিয়ারিংয়ে, সর্বাধিক ব্যবহৃত হয় ক্লিন আর্কিটেকচার + এমভিভিএম এবং রেডাক্স নিদর্শন।

ক্লিন আর্কিটেকচার + এমভিভিএম 3 টি স্তর নিয়ে গঠিত: ডোমেন, উপস্থাপনা, ডেটা স্তর। উপস্থাপনা স্তর এবং ডেটা সংগ্রহস্থল স্তর যেখানে ডোমেন স্তরের উপর নির্ভর করে:

Presentation Layer -> Domain Layer <- Data Repositories Layer

এবং উপস্থাপনা স্তরটিতে ভিউমোডেলস এবং ভিউগুলি (এমভিভিএম) রয়েছে:

Presentation Layer (MVVM) = ViewModels + Views
Domain Layer = Entities + Use Cases + Repositories Interfaces
Data Repositories Layer = Repositories Implementations + API (Network) + Persistence DB

এই নিবন্ধে, ক্লিন আর্কিটেকচার + এমভিভিএম https://tech.olx.com/clean-architecture-and-mvvm-on-ios-c9d167d9f5b3 এর আরও বিশদ বিবরণ রয়েছে

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.