ios - تمرير البيانات بين وحدات تحكم العرض




objective-c oop model-view-controller uiviewcontroller (25)

أنا جديد على نظام iOS و Objective-C ونموذج MVC بالكامل ، وأنا ملتصق بما يلي:

لدي وجهة نظر تعمل كنموذج إدخال بيانات وأريد أن أمنح المستخدم خيار تحديد منتجات متعددة. يتم سرد المنتجات في طريقة عرض أخرى باستخدام UITableViewController ولقد قمت بتمكين تحديدات متعددة.

سؤالي هو ، كيف يمكنني نقل البيانات من وجهة نظر إلى أخرى؟ UITableView الاختيارات على UITableView في مصفوفة ، ولكن كيف يمكنني تمرير ذلك مرة أخرى إلى طريقة عرض نموذج إدخال البيانات السابقة حتى يمكن حفظها مع البيانات الأخرى إلى Core Data عند إرسال النموذج؟

لقد تجولت حول ورؤية بعض الناس يعلنون صفيف في مندوب التطبيق. قرأت شيئًا عن Singletons لكنني لم أفهم ما هي هذه وأنا قرأت شيئًا حول إنشاء نموذج بيانات.

ما هي الطريقة الصحيحة لأداء هذا وكيف سأذهب بشأنه؟


Answers

You can save data in App delegate to access it across view controllers in your application. All you have to do is create a shared instance of app delegate

AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;

For Example

if you declare a NSArray object *arrayXYZ then you can access it in any view controller by appDelegate.arrayXYZ


In my case I used a singleton class which can work as a global object allowing accesses to the data from almost everywhere in the app. First thing is to build a singleton class. Please refer to the page," What should my Objective-C singleton look like? " And what I did to make the object globally accessible was simply import it in appName_Prefix.pch which is for applying import statement in every classes. To access this object and to use, I simply implemented class method to return the shared instance, which contains its own variables


I was searching this solution for long time, Atlast I found it. First of all declare all the objects in your SecondViewController.h file like

@interface SecondViewController: UIviewController 
{
    NSMutableArray *myAray;
    CustomObject *object;
}

Now in your implementation file allocate the memory for those objects like this

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
     self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
     if (self) 
     {
         // Custom initialization
         myAray=[[NSMutableArray alloc] init];
         object=[[CustomObject alloc] init];
     }
     return self;
}

Now you have allocated the memory for Array and object. now you can fill that memory before pushing this ViewController

Go to your SecondViewController.h and write two methods

-(void)setMyArray:(NSArray *)_myArray;
-(void)setMyObject:(CustomObject *)_myObject;

in implementation file you can implement the function

-(void)setMyArray:(NSArray *)_myArray
{
     [myArra addObjectsFromArray:_myArray];
}
-(void)setMyObject:(CustomObject *)_myObject
{
     [object setCustomObject:_myObject];
}

expecting that your CustomObject must have a setter function with it.

now your basic work is done. go to the place where you want to push the SecondViewController and do the following stuff

SecondViewController *secondView= [[SecondViewController alloc] initWithNibName:@"SecondViewController " bundle:[NSBundle MainBundle]] ;
[secondView setMyArray:ArrayToPass];
[secondView setMyObject:objectToPass];
[self.navigationController pushViewController:secondView animated:YES ];

Take care for spelling mistakes.


If you want to send data from one to another viewController, here's a way to it:

Say we have viewControllers: ViewController and NewViewController.

in ViewController.h

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController
{
    IBOutlet UITextField *mytext1,*mytext2,*mytext3,*mytext4;
}

@property (nonatomic,retain) IBOutlet UITextField *mytext1,*mytext2,*mytext3,*mytext4;

-(IBAction)goToNextScreen:(id)sender;

@end

in ViewController.m

#import "ViewController.h"

#import "NewViewController.h"

@implementation ViewController
@synthesize mytext1,mytext2,mytext3,mytext4;

-(IBAction)goToNextScreen:(id)sender
{
    NSArray *arr = [NSArray arrayWithObjects:mytext1.text,mytext2.text,mytext3.text,mytext4.text, nil];


    NewViewController *newVc = [[NewViewController alloc] initWithNibName:@"NewViewController" bundle:nil];

    newVc.arrayList = arr;

    [self.navigationController pushViewController:newVc animated:YES];

}

In NewViewController.h

#import <UIKit/UIKit.h>

@interface NewViewController : UITableViewController
{
    NSArray *arrayList;

    NSString *name,*age,*dob,*mobile;

}

@property(nonatomic, retain)NSArray *arrayList;

@end

In NewViewController.m

#import "NewViewController.h"

#import "ViewController.h"

@implementation NewViewController
@synthesize arrayList;

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{

    // Return the number of sections.
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{

    // Return the number of rows in the section.
    return [arrayList count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil)
    {
         cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];      
    }
    // Configure the cell...
    cell.textLabel.text = [arrayList objectAtIndex:indexPath.row];
    return cell;


}

@end

So this way we can pass the data from one viewcontroller to another view controller...


There are many answers to this questions offering many different ways to perform view controller communication that would indeed work, but I don't see anywhere mentioned which one are actually best to use and which ones to avoid.

In practice, in my opinion only a few solutions are recommended:

  • To pass data forward:
    • override the prepare(for:sender:) method of UIViewController when using a storyboard and segues
    • pass data through an initializer or through properties when performing view controller transitions thtough code
  • To pass data backwards
    • update the app shared state (which you can pass forward between view controllers with either one of the methods above)
    • use delegation
    • use an unwind segue

Solutions I recommend NOT to use:

  • Referencing the previous controller directly instead of using delegation
  • Sharing data through a singleton
  • Passing data through the app delegate
  • Sharing data through the user defaults
  • Passing data through notifications

These solutions, although working in the short term, introduce too many dependencies that will garble the architecture of the app and create more problems later.

For those interested, I wrote some articles that address these points more in depth and highlight the various drawbacks:


M في MVC هو من أجل "Model" وفي نموذج MVC ، فإن دور الفئات النموذجية هو إدارة بيانات البرنامج. النموذج هو عكس العرض - حيث تعرف طريقة عرض البيانات ، ولكنها لا تعرف شيئًا عن ما يجب فعله بالبيانات ، في حين يعرف النموذج كل شيء عن كيفية التعامل مع البيانات ، ولكن لا شيء حول كيفية عرضه. يمكن أن تكون النماذج معقدة ، ولكن ليس من الضروري أن تكون - قد يكون نموذج تطبيقك بسيطًا مثل مجموعة من السلاسل أو القواميس.

يتمثل دور وحدة التحكم في التوسط بين العرض والطراز. لذلك ، تحتاج إلى مرجع إلى كائن عرض واحد أو أكثر وكائن نموذج واحد أو أكثر. لنفترض أن نموذجك عبارة عن مصفوفة من القواميس ، حيث يمثل كل قاموس صفًا واحدًا في الجدول. يعرض عرض الجذر للتطبيق هذا الجدول ، وقد يكون مسؤولاً عن تحميل الصفيف من الملف. عندما يقرر المستخدم إضافة صف جديد إلى الجدول ، فإنه ينقر على بعض الأزرار وتقوم وحدة التحكم بإنشاء قاموس جديد (قابل للتغيير) وإضافته إلى الصفيف. من أجل ملء الصف ، تقوم وحدة التحكم بإنشاء وحدة تحكم في عرض التفاصيل وتعطيها القاموس الجديد. يملأ جهاز التحكم في عرض التفاصيل في القاموس ويعود. القاموس بالفعل جزء من النموذج ، لذلك لا شيء آخر يحتاج إلى أن يحدث.


Passing Data between FirstViewController to SecondViewController as below

فمثلا:

FirstViewController String value as

StrFirstValue = @"first";

so we can pass this value in second class using below step

1>We need to crate string object in SecondViewController.h file

NSString *strValue;

2>Need to declare property as below below declaration in .h file

@property (strong, nonatomic)  NSString *strSecondValue;

3>Need synthesize that value in FirstViewController.m file below header declaration

@synthesize strValue;

and in FirstViewController.h :

@property (strong, nonatomic)  NSString *strValue;

4>In FirstViewController,From which method we navigate to second view please write below code in that method.

SecondViewController *secondView= [[SecondViewController alloc]     
initWithNibName:@"SecondViewController " bundle:[NSBundle MainBundle]];

[secondView setStrSecondValue:StrFirstValue];

[self.navigationController pushViewController:secondView animated:YES ];

هناك طرق متعددة لمشاركة البيانات.

  1. يمكنك دائمًا مشاركة البيانات باستخدام NSUserDefaults . قم بتعيين القيمة التي تريد مشاركتها فيما يتعلق بمفتاح من اختيارك والحصول على القيمة من NSUserDefault المرتبط بهذا المفتاح في جهاز التحكم في العرض التالي.

    [[NSUserDefaults standardUserDefaults] setValue:value forKey:key]
    [[NSUserDefaults standardUserDefaults] objectForKey:key]
    
  2. يمكنك فقط إنشاء خاصية في viewcontrollerA . إنشاء كائن من viewcontrollerA في viewcontrollerB وتعيين القيمة المطلوبة لهذا الموقع.

  3. يمكنك أيضًا إنشاء تفويض مخصص لهذا الغرض.


There are tons of ways to do this and it's important to pick the right one. Probably one of the biggest architectural decisions lies on how the model code will be shared or accessed throughout the app.

I wrote a blog post about this a while back: Sharing Model Code . Here's a brief summary:

Shared data

One approach is to share pointers to the model objects between view controllers.

  • Brute force iteration on view controllers (in Navigation or Tab Bar Controller) to set the data
  • Set data in prepareForSegue (if storyboards) or init (if programmatic)

Since prepare for segue is the most common here is an example:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    var next = segue.destinationViewController as NextViewController
    next.dataSource = dataSource
}

Independent access

Another approach is to handle a screen full of data at a time and instead of coupling the view controllers to each other couple each view controller to single data source that they can get to independently.

The most common way I've seen this done is a singleton instance. So if your singleton object was DataAccess you could do the following in the viewDidLoad method of UIViewController:

func viewDidLoad() {
    super.viewDidLoad()
    var data = dataAccess.requestData()
}

There are addition tools that also help pass along data:

  • Key-Value Observing
  • NSNotification
  • Core Data
  • NSFetchedResultsController
  • Data Source

Core Data

The nice thing about Core Data is that it has inverse relationships. So if you want to just give a NotesViewController the notes object you can because it'll have an inverse relationship to something else like the notebook. If you need data on the notebook in the NotesViewController you can walk back up the object graph by doing the following:

let notebookName = note.notebook.name

Read more about this in my blog post: Sharing Model Code


يبدو أن هذا السؤال يحظى بشعبية كبيرة هنا على لذلك اعتقدت أنني سأحاول وإعطاء إجابة أفضل لمساعدة الناس بدءا من عالم iOS مثلي.

آمل أن تكون هذه الإجابة واضحة بما يكفي ليتفهم الناس وأنني لم أفقد أي شيء.

تمرير البيانات إلى الأمام

تمرير البيانات إلى الأمام إلى وحدة تحكم طريقة عرض من جهاز تحكم عرض آخر. يمكنك استخدام هذه الطريقة إذا أردت تمرير كائن / قيمة من جهاز عرض واحد إلى وحدة تحكم عرض أخرى قد تضغط عليها إلى مكدس تنقل.

على سبيل المثال ، سيكون لدينا ViewControllerA و ViewControllerB

لتمرير قيمة BOOL من ViewControllerA إلى ViewControllerB سنفعل ما يلي.

  1. في ViewControllerB.h إنشاء خاصية لـ BOOL

    @property (nonatomic, assign) BOOL isSomethingEnabled;
    
  2. في ViewControllerA تحتاج إلى إخباره عن ViewControllerB لذا استخدم a

    #import "ViewControllerB.h"
    

    ثم أين تريد تحميل طريقة العرض على سبيل المثال. didSelectRowAtIndex أو بعض IBAction تحتاج إلى تعيين الخاصية في ViewControllerB قبل دفعها إلى مكدس nav.

    ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil];
    viewControllerB.isSomethingEnabled = YES;
    [self pushViewController:viewControllerB animated:YES];
    

    سيؤدي هذا إلى تعيين isSomethingEnabled في ViewControllerB إلى قيمة BOOL YES .

تمرير البيانات إلى الأمام باستخدام Segues

إذا كنت تستخدم القصص المصورة ، فمن الأرجح أنك تستخدم المقاطع وسيحتاج هذا الإجراء لتمرير البيانات إلى الأمام. يشبه هذا أعلاه ولكن بدلاً من تمرير البيانات قبل ضغط جهاز عرض ، يمكنك استخدام أسلوب يسمى

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender

لذلك ViewControllerA BOOL من ViewControllerA إلى ViewControllerB سوف نقوم بما يلي:

  1. في ViewControllerB.h إنشاء خاصية لـ BOOL

    @property (nonatomic, assign) BOOL isSomethingEnabled;
    
  2. في ViewControllerA تحتاج إلى إخباره عن ViewControllerB لذا استخدم a

    #import "ViewControllerB.h"
    
  3. إنشاء segue من ViewControllerA إلى ViewControllerB على لوحة العمل وإعطائه معرف ، في هذا المثال سنطلق عليه "showDetailSegue"

  4. بعد ذلك ، نحتاج إلى إضافة الطريقة إلى ViewControllerA التي يتم استدعاؤها عند إجراء أي عملية فصل ، ولهذا السبب نحتاج إلى الكشف عن القطعة التي تم استدعاءها ثم القيام بشيء ما. في المثال الخاص بنا ، سوف نتحقق من وجود "showDetailSegue" وإذا تم تنفيذ ذلك ، ViewControllerB على تمرير قيمة BOOL إلى ViewControllerB

    -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
        if([segue.identifier isEqualToString:@"showDetailSegue"]){
            ViewControllerB *controller = (ViewControllerB *)segue.destinationViewController;
            controller.isSomethingEnabled = YES;
        }
    }
    

    إذا كان لديك وجهات نظركم جزءا لا يتجزأ في وحدة تحكم الملاحة تحتاج إلى تغيير الطريقة المذكورة أعلاه قليلا إلى ما يلي

    -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
        if([segue.identifier isEqualToString:@"showDetailSegue"]){
            UINavigationController *navController = (UINavigationController *)segue.destinationViewController;
            ViewControllerB *controller = (ViewControllerB *)navController.topViewController;
            controller.isSomethingEnabled = YES;
        }
    }
    

    سيؤدي هذا إلى تعيين isSomethingEnabled في ViewControllerB إلى قيمة BOOL YES .

تمرير البيانات مرة أخرى

لتمرير البيانات مرة أخرى من ViewControllerB إلى ViewControllerA تحتاج إلى استخدام البروتوكولات والمندوبين أو الكتل ، ويمكن استخدام هذا الأخير كآلية مقرونة بشكل فضفاض لإجراء الاستدعاءات.

للقيام بذلك ، سنجعل ViewControllerA مندوبًا لـ ViewControllerB . يسمح هذا لـ ViewControllerB بإرسال رسالة إلى ViewControllerA تمكننا من إرسال البيانات مرة أخرى.

بالنسبة لـ ViewControllerA ليتم تفويض ViewControllerB ، يجب أن يتوافق مع بروتوكول ViewControllerB الذي يتعين علينا تحديده. هذا يخبر ViewControllerA الطرق التي يجب تنفيذها.

  1. في ViewControllerB.h ، أدناه #import ، ولكن فوق @interface تقوم بتحديد البروتوكول.

    @class ViewControllerB;
    
    @protocol ViewControllerBDelegate <NSObject>
    - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item;
    @end
    
  2. التالي لا يزال في ViewControllerB.h تحتاج إلى إعداد خاصية delegate وتوليف في ViewControllerB.m

    @property (nonatomic, weak) id <ViewControllerBDelegate> delegate;
    
  3. في ViewControllerB نسميه رسالة على delegate عندما ViewControllerB وحدة تحكم المشاهدة.

    NSString *itemToPassBack = @"Pass this value back to ViewControllerA";
    [self.delegate addItemViewController:self didFinishEnteringItem:itemToPassBack];
    
  4. هذا كل شيء من أجل ViewControllerB . الآن في ViewControllerA.h ، أخبر ViewControllerA باستيراد ViewControllerB مع البروتوكول الخاص به.

    #import "ViewControllerB.h"
    
    @interface ViewControllerA : UIViewController <ViewControllerBDelegate>
    
  5. في ViewControllerA.m بتنفيذ الطريقة التالية من البروتوكول الخاص بنا

    - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item
    {
        NSLog(@"This was returned from ViewControllerB %@",item);
    }
    
  6. قبل دفع viewControllerB إلى viewControllerB نحتاج إلى إخبار ViewControllerB بأن ViewControllerA هو مندوبها ، وإلا ViewControllerA على خطأ.

    ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil];
    viewControllerB.delegate = self
    [[self navigationController] pushViewController:viewControllerB animated:YES];
    

المراجع


I like the idea of Model objects and Mock objects based on NSProxy to commit or discard data if what user selects can be cancelled.

It's easy to pass data around since it's single object or couple of objects and if you have let's say UINavigationController controller, you can keep the reference to model inside and all pushed view controllers can access it directly from navigation controller.


If you want to send data from one to another viewController, here's a way to it:

Say we have viewControllers: viewControllerA and viewControllerB

Now in viewControllerB.h

@interface viewControllerB : UIViewController {

  NSString *string;
  NSArray *array;

}

- (id)initWithArray:(NSArray)a andString:(NSString)s;

In viewControllerB.m

#import "viewControllerB.h"

@implementation viewControllerB

- (id)initWithArray:(NSArray)a andString:(NSString)s {

   array = [[NSArray alloc] init];
   array = a;

   string = [[NSString alloc] init];
   string = s;

}

In viewControllerA.m

#import "viewControllerA.h"
#import "viewControllerB.h"

@implementation viewControllerA

- (void)someMethod {

  someArray = [NSArray arrayWithObjects:@"One", @"Two", @"Three", nil];
  someString = [NSString stringWithFormat:@"Hahahahaha"];

  viewControllerB *vc = [[viewControllerB alloc] initWithArray:someArray andString:someString];

  [self.navigationController pushViewController:vc animated:YES];
  [vc release];

}

So this is how you can pass data from viewControllerA to viewControllerB without setting any delegate. ؛)


هناك بعض المعلومات الجيدة في العديد من الإجابات المقدمة ، ولكن لا يوجد عنوان يتناول السؤال بشكل كامل.

يطرح السؤال حول تمرير المعلومات بين وحدات التحكم في العرض. يسأل المثال المعين عن تمرير المعلومات بين المشاهدات ، ولكن نظرًا إلى الحداثة المعلنة لنظام التشغيل iOS ، فمن المحتمل أن يكون الملصق الأصلي يعني بين وحدات التحكم في العرض ، وليس بين المشاهدات (دون أي تدخل من أدوات التحكم في العرض). يبدو أن جميع الإجابات تركز على اثنين من وحدات التحكم في العرض ، ولكن ماذا لو تطور التطبيق ليحتاج إلى إشراك أكثر من اثنين من وحدات التحكم في العرض في تبادل المعلومات؟

سأل الملصق الأصلي أيضا عن Singletons واستخدام AppDelegate . هذه الأسئلة تحتاج إلى إجابة.

لمساعدة أي شخص آخر يبحث في هذا السؤال ، من يريد إجابة كاملة ، سأحاول تقديمه.

سيناريوهات التطبيق

فبدلاً من إجراء مناقشة افتراضية ومجردة للغاية ، فإنه يساعد على وضع تطبيقات ملموسة في الاعتبار. وللمساعدة في تحديد موقف مراقب ذي وضعين ووحدة تحكم أكثر من عرضين ، سأقوم بتحديد اثنين من سيناريوهات التطبيق الملموسة.

السيناريو الأول: تحتاج وحدتا تحكم في العرض كحد أقصى إلى مشاركة المعلومات. انظر الرسم البياني واحد.

هناك نوعان من وحدات تحكم العرض في التطبيق. هناك ViewControllerA (نموذج إدخال البيانات) ، و View Controller B (قائمة المنتجات). يجب أن تتطابق العناصر المحددة في قائمة المنتجات مع العناصر المعروضة في مربع النص في نموذج إدخال البيانات. في هذا السيناريو ، يجب أن يتواصل ViewControllerA و ViewControllerB مباشرة مع بعضها البعض دون وحدات تحكم أخرى في العرض.

السيناريو الثاني : يحتاج أكثر من وحدتي تحكم في العرض إلى مشاركة نفس المعلومات. انظر الرسم البياني الثاني.

هناك أربعة وحدات تحكم عرض في التطبيق. وهو تطبيق يستند إلى علامة التبويب لإدارة المخزون المنزلي. توفر وحدات التحكم الثلاثة عرض طرق عرض تمت تصفيتها بشكل مختلف من نفس البيانات:

  • ViewControllerA - عناصر فاخرة
  • ViewControllerB - العناصر غير المؤمنة
  • ViewControllerC - الجرد الرئيسية بالكامل
  • ViewControllerD - أضف نموذج عنصر جديد

في أي وقت يتم فيه إنشاء عنصر فردي أو تحريره ، يجب أن يتزامن أيضًا مع وحدات التحكم في العرض الأخرى. على سبيل المثال ، إذا أضفنا مركبًا في ViewControllerD ، ولكن لم يتم تأمينه بعد ، فيجب أن يظهر القارب عندما ينتقل المستخدم إلى ViewControllerA (عناصر فاخرة) ، وكذلك ViewControllerC (Invire Home Inventory) ، ولكن ليس عندما ينتقل المستخدم إلى ViewControllerB (العناصر غير المؤمنة). نحتاج إلى عدم الاكتفاء بإضافة عناصر جديدة ، ولكن أيضًا حذف العناصر (التي يمكن السماح بها من أي من وحدات التحكم في العرض الأربعة) ، أو تحرير العناصر الموجودة (والتي يمكن السماح بها من "إضافة نموذج عنصر جديد" ، إعادة تهيئة نفسه للتحرير).

نظرًا لأن جميع وحدات التحكم في العرض تحتاج إلى مشاركة البيانات نفسها ، يجب أن تظل جميع أجهزة العرض الأربعة في التزامن ، وبالتالي يجب أن يكون هناك نوع من الاتصال لجميع وحدات التحكم في العرض الأخرى ، في حالة تغيير أي وحدة تحكم في العرض المفرد للبيانات الأساسية. يجب أن يكون واضحًا إلى حد ما أننا لا نريد أن يتواصل كل جهاز تحكم في العرض مباشرة مع كل وحدة تحكم في العرض الأخرى في هذا السيناريو. في حالة عدم الوضوح ، فكر في ما إذا كان لدينا 20 وحدة تحكم مختلفة في العرض (بدلاً من 4 فقط). ما مدى صعوبة وعرضة للخطأ في إعلام كل من وحدات التحكم في العرض 19 الأخرى في أي وقت إجراء وحدة تحكم طريقة العرض واحد تغيير؟

الحلول: المندوبون ونمط المراقبين ، و Singletons

في السيناريو الأول ، لدينا العديد من الحلول القابلة للتطبيق ، كما قدمت إجابات أخرى

  • segues على
  • المندوبين
  • ضبط الخصائص على وحدات تحكم العرض مباشرة
  • NSUserDefaults (في الواقع اختيار ضعيف)

في السيناريو الثاني ، لدينا حلول أخرى قابلة للتطبيق:

  • نمط المراقب
  • سنغلتونس

المفرد هو مثال لفئة ، هذا المثال هو المثال الوحيد في الوجود خلال حياته. يحصل على singleton اسمه من حقيقة أنه هو مثيل واحد. عادةً ما يكون للمطورين الذين يستخدمون singletons طرقًا خاصة للطبقة للوصول إليها.

+ (HouseholdInventoryManager*) sharedManager; {
    static dispatch_once_t onceQueue;
    static HouseholdInventoryManager* _sharedInstance;

    // dispatch_once is guaranteed to only be executed once in the
    // lifetime of the application
    dispatch_once(&onceQueue, ^{
        _sharedInstance = [[self alloc] init];
    });
    return _sharedInstance;
}

الآن بعد أن فهمنا ما هو المفرد ، دعنا نناقش كيف يتناسب المفرد مع نمط الراصد. يتم استخدام نمط المراقب لكائن واحد للاستجابة للتغييرات بواسطة كائن آخر. في السيناريو الثاني ، لدينا أربعة وحدات تحكم عرض مختلفة ، الذين يريدون جميعًا معرفة التغييرات في البيانات الأساسية. يجب أن تنتمي "البيانات الأساسية" إلى مثيل واحد ، مفرد. يتم تحقيق "معرفة التغييرات" بملاحظة التغييرات التي تم إجراؤها على المفرد.

سيكون لتطبيق جرد المنازل مثيل واحد للفئة التي تم تصميمها لإدارة قائمة عناصر المخزون. يقوم المدير بإدارة مجموعة من الأدوات المنزلية. فيما يلي تعريف فئة لمدير البيانات:

#import <Foundation/Foundation.h>

@class JGCHouseholdInventoryItem;

@interface HouseholdInventoryManager : NSObject
/*!
 The global singleton for accessing application data
 */
+ (HouseholdInventoryManager*) sharedManager;


- (NSArray *) entireHouseholdInventory;
- (NSArray *) luxuryItems;
- (NSArray *) nonInsuredItems;

- (void) addHouseholdItemToHomeInventory:(JGCHouseholdInventoryItem*)item;
- (void) editHouseholdItemInHomeInventory:(JGCHouseholdInventoryItem*)item;
- (void) deleteHoueholdItemFromHomeInventory:(JGCHouseholdInventoryItem*)item;
@end

عند تغيير مجموعة عناصر مخزون المنزل ، يجب أن تكون أجهزة التحكم في العرض على علم بهذا التغيير. تعريف الفئة أعلاه لا يوضح كيف سيحدث هذا. نحن بحاجة إلى اتباع نمط المراقب. يجب أن مراقبة وحدات تحكم العرض رسميا في sharedManager. هناك طريقتان لمراقبة كائن آخر:

  • مراقبة القيمة الرئيسية (KVO)
  • NSNotificationCenter.

في السيناريو الثاني ، ليس لدينا خاصية واحدة لـ HouseholdInventoryManager يمكن ملاحظتها باستخدام KVO. نظرًا لأننا لا نمتلك خاصية واحدة يمكن ملاحظتها بسهولة ، يجب تطبيق نموذج المراقب ، في هذه الحالة ، باستخدام NSNotificationCenter. سيشترك كل عنصر من أجهزة التحكم في العرض الأربعة في الإشعارات ، وسيقوم "sharedManager" بإرسال إشعارات إلى مركز الإعلام عندما يكون ذلك مناسبًا. لا يحتاج مدير المخزون إلى معرفة أي شيء عن وحدات التحكم في العرض أو مثيلات أي فئات أخرى قد تكون مهتمة بمعرفة متى يتغير تجميع عناصر المخزون ؛ يعتني NSNotificationCenter بتفاصيل التنفيذ هذه. يشترك برنامج View Controllers ببساطة في الإشعارات ، ويقوم مدير البيانات ببساطة بإرسال الإشعارات.

يستفيد العديد من المبرمجين المبتدئين من حقيقة وجود مندوب تطبيق واحد دائمًا في عمر التطبيق ، والذي يمكن الوصول إليه عالميًا. يستخدم المبرمجون البادئون هذه الحقيقة في تخزين الأشياء والوظائف في تطبيق appDelegate كمتاحة للدخول من أي مكان آخر في التطبيق. فقط لأن AppDelegate هو singleton لا يعني أنه يجب استبدال كل المفردات الأخرى. هذه ممارسة ضعيفة لأنها تضع عبئًا كبيرًا على طبقة واحدة ، وتكسر الممارسات الجيدة المنحى. يجب أن يكون لكل فصل دور واضح يمكن تفسيره بسهولة ، وغالبًا ما يكون باسم الطبقة فقط.

في أي وقت يبدأ التفويض الخاص بالتطبيق بالانتشار ، ابدأ في إزالة الوظائف في المفردات. على سبيل المثال ، لا يجب ترك Core Data Stack في AppDelegate ، ولكن بدلاً من ذلك يجب وضعها في فئة خاصة بها ، وهي classDataManager.

المراجع


Create the property on next view controller .h and define getter and setter.

Add this property in NextVC.h on nextVC

@property (strong, nonatomic) NSString *indexNumber;

إضافة

@synthesize indexNumber; in NextVC.m

And last

NextVC *vc=[[NextVC alloc]init];

[email protected]"123";

[self.navigationController vc animated:YES];

1. Create the instance of first View Controller in the second View Controller and make its property @property (nonatomic,assign) .

2. Assign the SecondviewController instance of this view controller.

2. When you finish the selection operation copy the array to first View Controller,When u unload the SecondView ,FirstView will hold the Array Data.

Hope This Helps.


I know this is a beaten subject but for those looking to answer this question with a SWIFT slant and want a bare-bones example, here my go-to method for passing data if you are using a segue to get around.

It is similar to the above but without the buttons, labels and such. Just simply passing data from one view to the next.

Setup The Storyboard

There are three parts.

  1. The Sender
  2. The Segue
  3. The Receiver

This is a very simple view layout with a segue between them.

Here is the setup for the sender

Here is the setup for the receiver.

Lastly, the setup for the segue.

The View Controllers

We are keeping this simple so no buttons, not actions, we are simply moving data from the sender to the receiver when the application loads and then outputting the transmitted value to the console.

This page takes the initially loaded value and passes it along.

//
//  ViewControllerSender.swift
//  PassDataBetweenViews
//
//  Created by Chris Cantley on 8/25/15.
//  Copyright (c) 2015 Chris Cantley. All rights reserved.
//

import UIKit


class ViewControllerSender: UIViewController {

    // THE STUFF - put some info into a variable
    let favoriteMovie = "Ghost Busters"


    override func viewDidAppear(animated: Bool) {
        // PASS IDENTIFIER - go to the recieving view controller.
        self.performSegueWithIdentifier("goToReciever", sender: self)
    }

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

        //GET REFERENCE - ...to the receiver view.
        var viewControllerReceiver = segue.destinationViewController as? ViewControllerReceiver

        //PASS STUFF - pass the variable along to the target.
        viewControllerReceiver!.yourFavMovie = self.favoriteMovie

    }

}

This page just sends the value of the variable to the console when it loads. By this point our favorite movie should be in that variable.

//
//  ViewControllerReceiver.swift
//  PassDataBetweenViews
//
//  Created by Chris Cantley on 8/25/15.
//  Copyright (c) 2015 Chris Cantley. All rights reserved.
//

import UIKit

class ViewControllerReceiver: UIViewController {

    //Basic empty variable waiting for you to pass in your fantastic favorite movie.
    var yourFavMovie = ""

    override func viewDidLoad() {
        super.viewDidLoad()


        //And now we can view it in the console.
        println("The Movie is \(self.yourFavMovie)")

    }



}

That is how you can tackle it if you want to use a segue and you don't have your pages under a navigation controller.

Once it is run it should switch to the receiver view automatically and pass the value from the sender to the receiver, displaying the value in the console.


This is a really great tutorial for anyone that wants one. Here is the example code:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:@"myIdentifer]) {
        NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
        myViewController *destViewController = segue.destinationViewController;
        destViewController.name = [object objectAtIndex:indexPath.row];
    }
}

تمرير البيانات مرة أخرى من ViewController 2 (وجهة) لعرض المراقب 1 (المصدر) هو الشيء الأكثر إثارة للاهتمام. إذا افترضنا أنك تستخدم لوحة القصة ، فهذه هي جميع الطرق التي اكتشفتها:

  • مندوب
  • إعلام
  • افتراضيات المستخدم
  • الورقة المفردة

تمت مناقشتها هنا بالفعل.

لقد وجدت أن هناك المزيد من الطرق:

استخدام الاستدعاءات حظر:

استخدامه في طريقة prepareForSegue في VC1

NextViewController *destinationVC = (NextViewController *) segue.destinationViewController;
[destinationVC setDidFinishUsingBlockCallback:^(NextViewController *destinationVC)
{
    self.blockLabel.text = destination.blockTextField.text;
}];

-يستخدم لوحات قصصية استرخاء (خروج)

تطبيق طريقة باستخدام وسيطة UIStoryboardSegue في VC 1 ، مثل هذه الطريقة:

-(IBAction)UnWindDone:(UIStoryboardSegue *)segue { }

في storyboard ، اضغط على الزر "رجوع" إلى زر الخروج الأخضر (Unwind) الخاص بـ vc. الآن لديك segue "العودة" بحيث يمكنك استخدام الخاصية destinationViewController في prepareForSegue VC2 وتغيير أي خاصية VC1 قبل أن يعود.

  • خيار آخر لاستخدام القصص المصورة Undwind (خروج) - يمكنك استخدام الطريقة التي كتبتها في VC1

    -(IBAction)UnWindDone:(UIStoryboardSegue *)segue {
        NextViewController *nextViewController = segue.sourceViewController;
        self.unwindLabel.text = nextViewController.unwindPropertyPass;
    } 
    

    وفي الإعداد FORSorSegue من VC1 يمكنك تغيير أي خاصية تريد مشاركتها.

في كل من خيارات الاسترخاء يمكنك تعيين خاصية علامة من الزر والتحقق من ذلك في prepareForSegue.

آمل أن أضيف شيئا للمناقشة.

:) في صحتك.


This is not the way to do it, you should use delegates, I'll assume we have two view controllers ViewController1 and ViewController2 and this check thing is in the first one and when its state changes, you want to do something in ViewController2, to achieve that in the proper way, you should do the below:

Add a new file to your project (Objective-C Protocol) File -> New, now name it ViewController1Delegate or whatever you want and write these between the @interface and @end directives

@optional

- (void)checkStateDidChange:(BOOL)checked;

Now go to ViewController2.h and add

#import "ViewController1Delegate.h"

then change its definition to

@interface ViewController2: UIViewController<ViewController1Delegate>

Now go to ViewController2.m and inside the implementation add:

- (void)checkStateDidChange:(BOOL)checked {
     if (checked) {
           // Do whatever you want here
           NSLog(@"Checked");
     }
     else {
           // Also do whatever you want here
           NSLog(@"Not checked");
     }
}

Now go to ViewController1.h and add the following property:

@property (weak, nonatomic) id<ViewController1Delegate> delegate; 

Now if you are creating ViewController1 inside ViewController2 after some event, then you should do it this way using NIB files:

ViewController1* controller = [[NSBundle mainBundle] loadNibNamed:@"ViewController1" owner:self options:nil][0];
controller.delegate = self;
[self presentViewController:controller animated:YES completion:nil];

Now you are all set, whenever you detect the event of check changed in ViewController1, all you have to do is the below

[delegate checkStateDidChange:checked]; // You pass here YES or NO based on the check state of your control

Please tell me if there's anything that's not clear of if I didn't understand your question properly.


I am currently contributing to an open source solution to this problem through a project called MCViewFactory, which may be found here:

https://github.com/YetiHQ/manticore-iosviewfactory

The idea is imitate Android's intent paradigm, using a global factory to manage which view you are looking at and using "intents" to switch and pass data between views. All the documentation is on the github page, but here are some highlights:

You setup all your views in .XIB files and register them in the app delegate, while initializing the factory.

// Register activities

MCViewFactory *factory = [MCViewFactory sharedFactory];

// the following two lines are optional. 
[factory registerView:@"YourSectionViewController"]; 

Now, in your VC, anytime you want to move to a new VC and pass data, you create a new intent and add data to its dictionary (savedInstanceState). Then, just set the current intent of factory:

MCIntent* intent = [MCIntent intentWithSectionName:@"YourSectionViewController"];
[intent setAnimationStyle:UIViewAnimationOptionTransitionFlipFromLeft];
[[intent savedInstanceState] setObject:@"someValue" forKey:@"yourKey"];
[[intent savedInstanceState] setObject:@"anotherValue" forKey:@"anotherKey"];
// ...
[[MCViewModel sharedModel] setCurrentSection:intent];

All of your views that conform to this need to be subclasses of MCViewController, which allow you to override the new onResume: method, allowing you access to the data you've passed in.

-(void)onResume:(MCIntent *)intent {
    NSObject* someValue = [intent.savedInstanceState objectForKey:@"yourKey"];
    NSObject* anotherValue = [intent.savedInstanceState objectForKey:@"anotherKey"];

    // ...

    // ensure the following line is called, especially for MCSectionViewController
    [super onResume:intent];
}

Hope some of you find this solution useful/interesting.


I have seen a lot of people over complicating this using the didSelectRowAtPath method. I am using Core Data in my example.

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{

    //this solution is for using Core Data
    YourCDEntityName * value = (YourCDEntityName *)[[self fetchedResultsController] objectAtIndexPath: indexPath];

    YourSecondViewController * details = [self.storyboard instantiateViewControllerWithIdentifier:@"nameOfYourSecondVC"];//make sure in storyboards you give your second VC an identifier

    //Make sure you declare your value in the second view controller
    details.selectedValue = value;

    //Now that you have said to pass value all you need to do is change views
    [self.navigationController pushViewController: details animated:YES];

}

4 lines of code inside the method and you are done.


If you want to pass data from one controller to other try this code

FirstViewController.h

@property (nonatomic, retain) NSString *str;

SecondViewController.h

@property (nonatomic, retain) NSString *str1;

FirstViewController.m

- (void)viewDidLoad
   {
     // message for the second SecondViewController
     self.str = @"text message";

     [super viewDidLoad];
   }

-(IBAction)ButtonClicked
 {
   SecondViewController *secondViewController = [[SecondViewController alloc] initWithNibName:@"SecondViewController" bundle:nil];
   secondViewController.str1 = str;
  [self.navigationController pushViewController:secondViewController animated:YES];
 }

if you wants to pass data from ViewControlerOne to ViewControllerTwo try these..

do these in ViewControlerOne.h

 @property (nonatomic, strong) NSString *str1;

do these in ViewControllerTwo.h

 @property (nonatomic, strong) NSString *str2;

Synthesize str2 in ViewControllerTwo.m

@interface ViewControllerTwo ()
@end
@implementation ViewControllerTwo
@synthesize str2;

do these in ViewControlerOne.m

 - (void)viewDidLoad
 {
   [super viewDidLoad];

  // Data or string you wants to pass in ViewControllerTwo..
  self.str1 = @"hello world";

 }

on the buttons click event do this..

-(IBAction)ButtonClicked
{ //Navigation on buttons click event from ViewControlerOne to ViewControlerTwo with transferring data or string..
  ViewControllerTwo *objViewTwo=[self.storyboard instantiateViewControllerWithIdentifier:@"ViewControllerTwo"];
  obj.str2=str1;
  [self.navigationController pushViewController: objViewTwo animated:YES];
}

do these in ViewControllerTwo.m

- (void)viewDidLoad
{
 [super viewDidLoad];
  NSLog(@"%@",str2);
}

بعد المزيد من الأبحاث ، بدا أن البروتوكولات والمندوبين هي الطريقة الصحيحة التي يفضلها Apple للقيام بذلك.

انتهى بي الأمر باستخدام هذا المثال

مشاركة البيانات بين وحدات التحكم في العرض والكائنات الأخرى @ iPhone Dev SDK

عملت بشكل جيد وسمحت لي لتمرير سلسلة ومجموعة إلى الأمام والخلف بين وجهات نظري.

شكرا لجميع التعليمات الخاصة بك


الطرق المجردة هي دائما الظاهري. لا يمكن أن يكون لها تنفيذ.

هذا هو الفرق الرئيسي.

بشكل أساسي ، يمكنك استخدام طريقة افتراضية إذا كان لديك تنفيذ "افتراضي" لها وتريد السماح للأفراد بتغيير سلوكها.

باستخدام الطريقة المجردة ، فإنك تجبر المتحدرين على توفير التنفيذ.





ios objective-c oop model-view-controller uiviewcontroller