কোনও ইউআইটিএবলভিউ ঘরের ভিতরে ইউআরএল থেকে অ্যাসিঙ্ক চিত্র লোড হচ্ছে - স্ক্রোল করার সময় চিত্রটি ভুল চিত্রে পরিবর্তিত হয়


158

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

#define kBgQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)

- (void)viewDidLoad
{
    [super viewDidLoad];
    dispatch_async(kBgQueue, ^{
        NSData* data = [NSData dataWithContentsOfURL: [NSURL URLWithString:
                                                       @"http://myurl.com/getMovies.php"]];
        [self performSelectorOnMainThread:@selector(fetchedData:)
                               withObject:data waitUntilDone:YES];
    });
}

-(void)fetchedData:(NSData *)data
{
    NSError* error;
    myJson = [NSJSONSerialization
              JSONObjectWithData:data
              options:kNilOptions
              error:&error];
    [_myTableView reloadData];
}    

- (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.
    // Usually the number of items in your array (the one that holds your list)
    NSLog(@"myJson count: %d",[myJson count]);
    return [myJson count];
}
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

        myCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
        if (cell == nil) {
            cell = [[myCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
        }

        dispatch_async(kBgQueue, ^{
        NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://myurl.com/%@.jpg",[[myJson objectAtIndex:indexPath.row] objectForKey:@"movieId"]]]];

            dispatch_async(dispatch_get_main_queue(), ^{
        cell.poster.image = [UIImage imageWithData:imgData];
            });
        });
         return cell;
}

... ...

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

            myCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
            if (cell == nil) {
                cell = [[myCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
            }
    NSURL* url = [NSURL URLWithString:[NSString stringWithFormat:@"http://myurl.com/%@.jpg",[[myJson objectAtIndex:indexPath.row] objectForKey:@"movieId"]]];
    NSURLRequest* request = [NSURLRequest requestWithURL:url];


    [NSURLConnection sendAsynchronousRequest:request
                                       queue:[NSOperationQueue mainQueue]
                           completionHandler:^(NSURLResponse * response,
                                               NSData * data,
                                               NSError * error) {
                               if (!error){
                                   cell.poster.image = [UIImage imageWithData:data];
                                   // do whatever you want with image
                               }

                           }];
     return cell;
}

5
আপনি প্রকৃত কক্ষে তথ্য সঞ্চয় করার চেষ্টা করছেন। এটা খারাপ, খুব খারাপ। আপনার তথ্য এন অ্যারে (বা অনুরূপ কিছু) সঞ্চয় করা উচিত এবং তারপরে এটি সেলগুলিতে প্রদর্শন করা উচিত। এই ক্ষেত্রে তথ্যটি হ'ল আসল ইউআইআইমেজ। হ্যাঁ এটিকে অবিচ্ছিন্নভাবে লোড করুন তবে এটিকে একটি অ্যারেতে লোড করুন।
ফগমিস্টার

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

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

1
তিনি যা করছেন তা টেবিলের সেই ঘরে সে একবার স্ক্রোল করার সময় ডাউনলোডকে বাধ্য করবে। ছবিগুলি অবিচ্ছিন্নভাবে সংরক্ষণ করা হয় কিনা তা তার উপর নির্ভর করে, তবে কমপক্ষে সেগুলি টেবিলভিউয়ের লাইফ টাইমের জন্য সংরক্ষণ করুন।
ফোগমিস্টার

1
ঠিক: D এইভাবে আপনাকে কেবল একবার URL থেকে চিত্রটি আনতে হবে। আপনি এটি ফেসবুক ফ্রেন্ড পিকারের মতো জিনিসগুলিতে দেখতে পাবেন। আপনি যখন এটি শুরু করেন সমস্ত অবতারগুলি ধূসর স্থানধারক। তারপরে আপনি যখন স্ক্রোল করবেন তখন এগুলি যেভাবে সরানো হবে সেগুলি তারা পূরণ করে। তবে তারপরে আপনি যখন দেখানো কোনও ঘরে ফিরে স্ক্রোল করবেন তখন তা তাত্ক্ষণিকভাবে ইতিমধ্যে ডাউনলোড করা চিত্রটি প্রদর্শিত হবে।
ফগমিস্টার

উত্তর:


230

ধরে নিই যে আপনি দ্রুত কৌশলগত সমাধানের সন্ধান করছেন, আপনার কী করা দরকার তা নিশ্চিত করা উচিত যে সেল ইমেজটি আরম্ভ করা হয়েছে এবং সেই সাথে যে ঘরটির সারিটি এখনও দৃশ্যমান, যেমন:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    MyCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];

    cell.poster.image = nil; // or cell.poster.image = [UIImage imageNamed:@"placeholder.png"];

    NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://myurl.com/%@.jpg", self.myJson[indexPath.row][@"movieId"]]];

    NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if (data) {
            UIImage *image = [UIImage imageWithData:data];
            if (image) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    MyCell *updateCell = (id)[tableView cellForRowAtIndexPath:indexPath];
                    if (updateCell)
                        updateCell.poster.image = image;
                });
            }
        }
    }];
    [task resume];

    return cell;
}

উপরের কোডটি কোষটি পুনরায় ব্যবহার করা হয়েছে এমনটি থেকে উদ্ভূত কয়েকটি সমস্যার সমাধান করেছে:

  1. আপনি ব্যাকগ্রাউন্ড অনুরোধ শুরু করার আগে সেল চিত্রটি আরম্ভ করছেন না (অর্থাত নতুন চিত্রটি ডাউনলোড করার সময় শনাক্তকৃত সেলটির জন্য শেষ চিত্রটি এখনও দৃশ্যমান হবে)। নিশ্চিত করুন কোন ইমেজ দেখার সম্পত্তি বা অন্যথায় আপনি ইমেজ ঝিকিমিকি দেখতে পাবেন।nilimage

  2. আরও সূক্ষ্ম ইস্যুটি হ'ল সত্যই ধীর নেটওয়ার্কে আপনার অ্যাসিনক্রোনাস অনুরোধটি সেল স্ক্রিনে স্ক্রোল করার আগে শেষ নাও হতে পারে। সেই সারির সেলটি এখনও দৃশ্যমান কিনা তা দেখতে আপনি UITableViewপদ্ধতিটি cellForRowAtIndexPath:(একই নামকরণ UITableViewDataSourceপদ্ধতিতে বিভ্রান্ত না হওয়ার জন্য tableView:cellForRowAtIndexPath:) ব্যবহার করতে পারেন। এই nilকক্ষটি দৃশ্যমান না হলে এই পদ্ধতিটি ফিরে আসবে ।

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

  3. কিছুটা হলেও প্রশ্নের সাথে সম্পর্কিত নয়, আমি এখনও আধুনিক কনভেনশন এবং এপিআইতে এটি আপডেট করার জন্য বাধ্যতামূলক অনুভব করেছি, উল্লেখযোগ্য:

    • পটভূমি সারি NSURLSessionপ্রেরণ না করে ব্যবহার করুন -[NSData contentsOfURL:];

    • এর dequeueReusableCellWithIdentifier:forIndexPath:পরিবর্তে ব্যবহার করুন dequeueReusableCellWithIdentifier:(তবে সেই শনাক্তকারীর জন্য সেল প্রোটোটাইপ বা নিবন্ধক শ্রেণী বা এনআইবি ব্যবহার নিশ্চিত করুন); এবং

    • আমি একটি শ্রেণীর নাম ব্যবহার করেছি যা কোকো নামকরণ কনভেনশনগুলির সাথে সামঞ্জস্য করে (অর্থাত্ বড় হাতের অক্ষর দিয়ে শুরু করুন)।

এমনকি এই সংশোধনগুলি নিয়েও কিছু সমস্যা রয়েছে:

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

  2. আমরা স্ক্রিনটি বাইরে স্ক্রোল করে এমন কক্ষগুলির জন্য অনুরোধগুলি বাতিল করছি না। সুতরাং, আপনি যদি দ্রুত 100 তম সারিতে স্ক্রোল করেন তবে সেই সারিটির চিত্রটি আগের 99 টি সারিগুলির অনুরোধগুলির পিছনে ব্যাকলগ করা যেতে পারে যা এখন পর্যন্ত দেখা যায় না। আপনি সর্বদা এটি নিশ্চিত করতে চান যে আপনি সেরা ইউএক্স-এর জন্য দৃশ্যমান কক্ষগুলির জন্য অনুরোধকে অগ্রাধিকার দিয়েছেন।

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


1
ধন্যবাদ। আমি বিশ্বাস করি আপনার উত্তরটি সম্পাদনা করা দরকার। আপডেট updateCell.poster.image = nilকরার জন্য cell.poster.image = nil;সেলকে ডেকে আনার আগে ডাকা হয়।
সেজেভ

1
আমার অ্যাপ্লিকেশন প্রচুর জসন ব্যবহার করে তাই AFNetworkingঅবশ্যই যাওয়ার উপায়। আমি এটি সম্পর্কে জানতাম তবে এটি ব্যবহার করতে অলস ছিল। আমি কেবল প্রশংসা করছি যে তাদের সহজ কোডের লাইনের সাথে ক্যাশেগুলি কীভাবে কাজ করে। [imageView setImageWithURL:<#(NSURL *)#> placeholderImage:<#(UIImage *)#>];
সেজেভ

2
উপরোক্ত এবং এসডিওয়েবআইমেজ এর সমস্ত চেষ্টা করে দেখেন (আসলে এখানেই থামানো হয়েছিল এবং এএফ নেটওয়ার্কিং চেষ্টা করার প্রয়োজনও ছিল না) এবং এটি ছিল সেরা পছন্দ। ধন্যবাদ @ রব।
সোমবার

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

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

15

/ * আমি এটি এভাবেই করেছি এবং এটিও পরীক্ষা করেছি * /

পদক্ষেপ 1 = ভিউডিডলড পদ্ধতিতে টেবিলের জন্য কাস্টম সেল শ্রেণি (টেবিলের প্রোটোটাইপ সেল ক্ষেত্রে) বা নিব (কাস্টম সেলের জন্য কাস্টম নিবের ক্ষেত্রে) নিবন্ধন করুন:

[self.yourTableView registerClass:[CustomTableViewCell class] forCellReuseIdentifier:@"CustomCell"];

অথবা

[self.yourTableView registerNib:[UINib nibWithNibName:@"CustomTableViewCell" bundle:nil] forCellReuseIdentifier:@"CustomCell"];

পদক্ষেপ 2 = ইউআইটিএবলভিউয়ের "ডেকিউরউজেবলসেসিবেল উইথআইডেন্টিফায়ার: ফর ইন্ডেক্সপথ:" পদ্ধতিটি ব্যবহার করুন (এর জন্য আপনাকে অবশ্যই শ্রেণি বা নিবি রেজিস্ট্রেশন করতে হবে):

   - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
            CustomTableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"CustomCell" forIndexPath:indexPath];

            cell.imageViewCustom.image = nil; // [UIImage imageNamed:@"default.png"];
            cell.textLabelCustom.text = @"Hello";

            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                // retrive image on global queue
                UIImage * img = [UIImage imageWithData:[NSData dataWithContentsOfURL:     [NSURL URLWithString:kImgLink]]];

                dispatch_async(dispatch_get_main_queue(), ^{

                    CustomTableViewCell * cell = (CustomTableViewCell *)[tableView cellForRowAtIndexPath:indexPath];
                  // assign cell image on main thread
                    cell.imageViewCustom.image = img;
                });
            });

            return cell;
        }

1
চূড়ান্ত ব্লকের মধ্যে সেলফোর্ডআউটআইডেক্সপথকে কল করা কি পুরো জিনিসটিকে দ্বিতীয়বার বহিষ্কার করার কারণ নয়?
মার্ক ব্রিজগুলি

@ মার্কব্রিজ, না। আসলে আমি এখানে টেবিলভিউর সেলফোর্ডআউটইন্ডেক্সপথ পদ্ধতিটি কল করছি। একই নামের সাথে টেবিলভিউর ডেটাসোর্স পদ্ধতিতে বিভ্রান্ত হবেন না। এটি প্রয়োজন, এটিকে [স্ব টেবিলভিউ: টেবিলভিউ সেলফোর্ডআউটইন্ডেক্সপথ: সূচিপথ] এর মতো বলা যেতে পারে; আশা করি এটি আপনার বিভ্রান্তি দূর করবে।
নীতেশ বোরাড

14

একাধিক ফ্রেমওয়ার্ক রয়েছে যা এই সমস্যাটি সমাধান করে। মাত্র কয়েক নাম:

সুইফট:

উদ্দেশ্য গ:


বিবেচনা করার মতো অন্যান্য ফ্রেমওয়ার্ক থাকলে দয়া করে আপনার পরামর্শগুলি যুক্ত করুন।
কিয়ান

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

প্রশ্নটি থেকে সমস্যাটি হ'ল লেখক কোষটি পুনরায় ব্যবহার করেছেন কিনা তা পরীক্ষা করে দেখছিলেন না। এটি একটি খুব প্রাথমিক সমস্যা যা এসডিওয়েবআইমেজ সহ frame ফ্রেমওয়ার্কগুলি দ্বারা সমাধান করা হয়েছে।
কিয়ান

আইওএস 8-এর পর থেকে এসডিওয়েবআইমেজ খুব পিছিয়ে আছে, এটি আমার অন্যতম অনুকূল ফ্রেমওয়ার্ক ছিল তবে এখন আমি পিনরেট আইমেজটি ব্যবহার শুরু করছি যা পুনরায় কার্যকরভাবে কাজ করে।
জোয়ান কার্ডোনা

@ বার্তোমিজেজ সিমিয়াজিক আপনি ঠিক বলেছেন, এই সমস্যাটি এসডিউইবিমাজে সমাধান করেছেন না
জানুয়ারী

9

সুইফট 3

আমি এনএসসি ক্যাচ ব্যবহার করে ইমেজ লোডারটির জন্য নিজের আলো প্রয়োগ করি। কোনও সেল ইমেজ ঝলকানি!

ImageCacheLoader.swift

typealias ImageCacheLoaderCompletionHandler = ((UIImage) -> ())

class ImageCacheLoader {
    
    var task: URLSessionDownloadTask!
    var session: URLSession!
    var cache: NSCache<NSString, UIImage>!
    
    init() {
        session = URLSession.shared
        task = URLSessionDownloadTask()
        self.cache = NSCache()
    }
    
    func obtainImageWithPath(imagePath: String, completionHandler: @escaping ImageCacheLoaderCompletionHandler) {
        if let image = self.cache.object(forKey: imagePath as NSString) {
            DispatchQueue.main.async {
                completionHandler(image)
            }
        } else {
            /* You need placeholder image in your assets, 
               if you want to display a placeholder to user */
            let placeholder = #imageLiteral(resourceName: "placeholder")
            DispatchQueue.main.async {
                completionHandler(placeholder)
            }
            let url: URL! = URL(string: imagePath)
            task = session.downloadTask(with: url, completionHandler: { (location, response, error) in
                if let data = try? Data(contentsOf: url) {
                    let img: UIImage! = UIImage(data: data)
                    self.cache.setObject(img, forKey: imagePath as NSString)
                    DispatchQueue.main.async {
                        completionHandler(img)
                    }
                }
            })
            task.resume()
        }
    }
}

ব্যবহারের উদাহরণ

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
    let cell = tableView.dequeueReusableCell(withIdentifier: "Identifier")
    
    cell.title = "Cool title"

    imageLoader.obtainImageWithPath(imagePath: viewModel.image) { (image) in
        // Before assigning the image, check whether the current cell is visible
        if let updateCell = tableView.cellForRow(at: indexPath) {
            updateCell.imageView.image = image
        }
    }    
    return cell
}

3
আমি আপনাকে ধন্যবাদ বলতে চাই। তবে কোডটিতে কিছুটা সমস্যা আছে। যদি তথ্য = চেষ্টা করে? ডেটা (বিষয়বস্তু: ইউআরএল) {// দয়া করে ইউআরএলটি লোকেশনটিতে প্রতিস্থাপন করুন। এটি অনেক লোককে সাহায্য করবে।
কার্ল

2
কোডটি যেমন রয়েছে তেমনি আপনি দুবার ফাইলটি নেটওয়ার্কের মাধ্যমে ডাউনলোড করুন: ডাউনলোডডটেক্সে একবার, একবার ডেটা (cntentsOf :) দিয়ে। আপনার অবশ্যই ইউআরএলের স্থানে ব্যবহারকারীর অবস্থান অবশ্যই তৈরি করা উচিত কারণ ডাউনলোড টাস্কটি কেবলমাত্র নেটওয়ার্কের মাধ্যমে ডাউনলোড করে একটি অস্থায়ী ফাইলে ডেটা লিখবে এবং আপনাকে স্থানীয় ইউআরএল (আপনার ক্ষেত্রে অবস্থান) দেয় passes সুতরাং ডেটাটিকে স্থানীয় url এ নির্দেশ করা দরকার যাতে এটি কেবল ফাইল থেকে পড়ে।
স্টাফেন ডি লুকা

ব্যবহারের উদাহরণে, এটি কি "ইমেজক্যাচলোডার.ওবেন্টইমেজওয়াইথপথ (চিত্রপথ: ভিউমোডেল.আইমেজ) ......." হওয়ার কথা?
টিম ক্রুর্গ

খুব দ্রুত স্ক্রোল করার সময় কাজ করবে না, সেল পুনরায় ব্যবহারের কারণে চিত্রগুলি বহুবার অদলবদল করবে।
জুয়ান বোয়েরো

5

এখানে সুইফ্ট সংস্করণ (@ নীতেশ বোড়াদ উদ্দেশ্য সি কোড ব্যবহার করে): -

   if let img: UIImage = UIImage(data: previewImg[indexPath.row]) {
                cell.cardPreview.image = img
            } else {
                // The image isn't cached, download the img data
                // We should perform this in a background thread
                let imgURL = NSURL(string: "webLink URL")
                let request: NSURLRequest = NSURLRequest(URL: imgURL!)
                let session = NSURLSession.sharedSession()
                let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
                    let error = error
                    let data = data
                    if error == nil {
                        // Convert the downloaded data in to a UIImage object
                        let image = UIImage(data: data!)
                        // Store the image in to our cache
                        self.previewImg[indexPath.row] = data!
                        // Update the cell
                        dispatch_async(dispatch_get_main_queue(), {
                            if let cell: YourTableViewCell = tableView.cellForRowAtIndexPath(indexPath) as? YourTableViewCell {
                                cell.cardPreview.image = image
                            }
                        })
                    } else {
                        cell.cardPreview.image = UIImage(named: "defaultImage")
                    }
                })
                task.resume()
            }

3

সর্বোত্তম উত্তরটি এটি করার সঠিক উপায় নয় :(। আপনি আসলে মডেলটির সাথে সূচিপত্রকে আবদ্ধ করেন যা সর্বদা ভাল নয় gine ধারণা করুন যে চিত্র লোড করার সময় কিছু সারি যুক্ত করা হয়েছে given এখন দেওয়া ইনডেক্সপথের সেলটি পর্দায় উপস্থিত রয়েছে, তবে চিত্রটি পরিস্থিতিটি আর সঠিক নয়! পরিস্থিতিটি প্রতিরূপ করা খুব সম্ভব নয় এবং এটি সম্ভব।

এমভিভিএম পদ্ধতির ব্যবহার করা, ভিউমোডেলের সাথে ভিউমোডেল সহ সেলটি বেঁধে রাখা এবং ভিউমোডলে চিত্র লোড করা (সুইচটোলেস্টেস্ট পদ্ধতির সাথে রিঅ্যাকটিভ কোকো সিগন্যাল বরাদ্দ করা), তারপরে এই সংকেতটি সাবস্ক্রাইব করুন এবং ইমেজটি ঘরে সেল করুন! ;)

আপনার মনে রাখতে হবে এমভিভিএমকে অপব্যবহার করবেন না। ভিউগুলি মরে যেতে হবে সহজ! যদিও ভিউমোডেলগুলি পুনরায় ব্যবহারযোগ্য হওয়া উচিত! এজন্য নিয়ামকটিতে ভিউ (ইউআইটিএবলভিউসেল) এবং ভিউমোডেলকে বাঁধাই খুব গুরুত্বপূর্ণ।


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

2
আমি কিছুটা পেডেন্টিক শব্দ করতে পারি তবে ভিউ থেকে যে কোনও ধরণের যুক্তি সঞ্চার করা এই আর্কিটেকচারটি আপত্তিজনক ব্যবহার করছে।
Badeleux

3

আমার ক্ষেত্রে এটি চিত্রের ক্যাশিংয়ের কারণে হয়নি (ব্যবহৃত এসডওয়েবআইমেজ)। এটি কাস্টম সেলের ট্যাগ ইনডেক্সপথ.রোজের সাথে মেলে না।

সেলফোর্ডরোআউটআইডেক্সপথে:

1) আপনার কাস্টম ঘরে একটি সূচক মান নির্ধারণ করুন। এই ক্ষেত্রে,

cell.tag = indexPath.row

২) মূল থ্রেডে, ছবিটি বরাদ্দের আগে, ছবিটি ট্যাগের সাথে মিলে এটি সংশ্লিষ্ট কক্ষের কিনা তা পরীক্ষা করুন।

dispatch_async(dispatch_get_main_queue(), ^{
   if(cell.tag == indexPath.row) {
     UIImage *tmpImage = [[UIImage alloc] initWithData:imgData];
     thumbnailImageView.image = tmpImage;
   }});
});

2

আপনাকে "রব" ধন্যবাদ .... ইউআইকোলিকেশনভিউতে আমার একই সমস্যা ছিল এবং আপনার উত্তর আমাকে আমার সমস্যার সমাধান করতে সহায়তা করে। আমার কোডটি এখানে:

 if ([Dict valueForKey:@"ImageURL"] != [NSNull null])
    {
        cell.coverImageView.image = nil;
        cell.coverImageView.imageURL=nil;

        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

            if ([Dict valueForKey:@"ImageURL"] != [NSNull null] )
            {
                dispatch_async(dispatch_get_main_queue(), ^{

                    myCell *updateCell = (id)[collectionView cellForItemAtIndexPath:indexPath];

                    if (updateCell)
                    {
                        cell.coverImageView.image = nil;
                        cell.coverImageView.imageURL=nil;

                        cell.coverImageView.imageURL=[NSURL URLWithString:[Dict valueForKey:@"ImageURL"]];

                    }
                    else
                    {
                        cell.coverImageView.image = nil;
                        cell.coverImageView.imageURL=nil;
                    }


                });
            }
        });

    }
    else
    {
        cell.coverImageView.image=[UIImage imageNamed:@"default_cover.png"];
    }

আমার জন্য, mycell *updateCell = (id)[collectionView cellForItemAtIndexPath:indexPath];কখনই শূন্য নয়, তাই এর কোনও প্রভাব নেই।
carbocation

1
আপনি আপনার সেলটি দৃশ্যমান কিনা তা পরীক্ষা করে দেখতে পারেন: এর জন্য (মাইसेल * আপডেটসেল ইন কালেকশনভিউ.ভিজিবলসেলস)) সেলভিজিবল = হ্যাঁ; } if (সেলভিজিবল) {সেল.কোভারআইজামভিউ.আইমেজ ইউআরএল = [এনএসআরএল ইউআরএল উইথ স্ট্রিং: [ডিক্ট ভ্যালোরফেরকি: @ "ইমেজ ইউআরএল"]]; } এটি আমার
পক্ষেও

@ স্নেহা ইয়েপ, আপনি এটির মধ্য দিয়ে পুনরাবৃত্তি করে এটি দৃশ্যমান তা পরীক্ষা করে দেখতে পারেন visibleCells, তবে আমার সন্দেহ [collectionView cellForItemAtIndexPath:indexPath]হয় যে এটি ব্যবহার করা আরও দক্ষ (
রব

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

2
 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{
        MyCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];

        cell.poster.image = nil; // or cell.poster.image = [UIImage imageNamed:@"placeholder.png"];

        NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://myurl.com/%@.jpg", self.myJson[indexPath.row][@"movieId"]]];

        NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            if (data) {
                UIImage *image = [UIImage imageWithData:data];
                if (image) {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        MyCell *updateCell = (id)[tableView cellForRowAtIndexPath:indexPath];
                        if (updateCell)
                            updateCell.poster.image = image;
                    });
                }
            }
        }];
        [task resume];

        return cell;
    }

0

আমি মনে করি আপনি ব্যাকগ্রাউন্ডে ঘরের জন্য চিত্র লোড করার সময় আপনার সেল লোডিংটি গতি বাড়িয়ে তুলতে চান। তার জন্য আমরা নিম্নলিখিত পদক্ষেপগুলি করেছি:

  1. ফাইলটি চেক করা নথির ডিরেক্টরিতে উপস্থিত রয়েছে বা নেই।

  2. যদি না হয় তবে প্রথমবারের জন্য চিত্রটি লোড করা এবং এটি আমাদের ফোনের নথি ডিরেক্টরিতে সংরক্ষণ করা। আপনি যদি ফোনে ছবিটি সংরক্ষণ করতে না চান তবে আপনি পটভূমিতে সরাসরি সেল চিত্রগুলি লোড করতে পারেন।

  3. এখন লোডিং প্রক্রিয়া:

কেবল অন্তর্ভুক্ত: #import "ManabImageOperations.h"

কোডটি কোনও ঘরের জন্য নীচের মতো:

NSString *imagestr=[NSString stringWithFormat:@"http://www.yourlink.com/%@",[dictn objectForKey:@"member_image"]];

        NSString *docDir=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0];
        NSLog(@"Doc Dir: %@",docDir);

        NSString  *pngFilePath = [NSString stringWithFormat:@"%@/%@",docDir,[dictn objectForKey:@"member_image"]];

        BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:pngFilePath];
        if (fileExists)
        {
            [cell1.memberimage setImage:[UIImage imageWithContentsOfFile:pngFilePath] forState:UIControlStateNormal];
        }
        else
        {
            [ManabImageOperations processImageDataWithURLString:imagestr andBlock:^(NSData *imageData)
             {
                 [cell1.memberimage setImage:[[UIImage alloc]initWithData: imageData] forState:UIControlStateNormal];
                [imageData writeToFile:pngFilePath atomically:YES];
             }];
}

ManabImageOperations.h:

#import <Foundation/Foundation.h>

    @interface ManabImageOperations : NSObject
    {
    }
    + (void)processImageDataWithURLString:(NSString *)urlString andBlock:(void (^)(NSData *imageData))processImage;
    @end

ManabImageOperations.m:

#import "ManabImageOperations.h"
#import <QuartzCore/QuartzCore.h>
@implementation ManabImageOperations

+ (void)processImageDataWithURLString:(NSString *)urlString andBlock:(void (^)(NSData *imageData))processImage
{
    NSURL *url = [NSURL URLWithString:urlString];

    dispatch_queue_t callerQueue = dispatch_get_main_queue();
    dispatch_queue_t downloadQueue = dispatch_queue_create("com.myapp.processsmagequeue", NULL);
    dispatch_async(downloadQueue, ^{
        NSData * imageData = [NSData dataWithContentsOfURL:url];

        dispatch_async(callerQueue, ^{
            processImage(imageData);
        });
    });
  //  downloadQueue=nil;
    dispatch_release(downloadQueue);

}
@end

দয়া করে উত্তরটি দেখুন এবং কোনও সমস্যা দেখা দিলে মন্তব্য করুন ...


0

কেবল পরিবর্তন,

dispatch_async(kBgQueue, ^{
     NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:   [NSString stringWithFormat:@"http://myurl.com/%@.jpg",[[myJson objectAtIndex:indexPath.row] objectForKey:@"movieId"]]]];
     dispatch_async(dispatch_get_main_queue(), ^{
        cell.poster.image = [UIImage imageWithData:imgData];
     });
 });

মধ্যে

    dispatch_async(kBgQueue, ^{
         NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:   [NSString stringWithFormat:@"http://myurl.com/%@.jpg",[[myJson objectAtIndex:indexPath.row] objectForKey:@"movieId"]]]];
         cell.poster.image = [UIImage imageWithData:imgData];
         dispatch_async(dispatch_get_main_queue(), ^{
            [self.tableView reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
         });
     });

0

আপনি কেবল আপনার ইউআরএল পাস করতে পারেন,

NSURL *url = [NSURL URLWithString:@"http://www.myurl.com/1.png"];
NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData * _Nullable data,    NSURLResponse * _Nullable response, NSError * _Nullable error) {
    if (data) {
        UIImage *image = [UIImage imageWithData:data];
        if (image) {
            dispatch_async(dispatch_get_main_queue(), ^{
                    yourimageview.image = image;
            });
        }
    }
}];
[task resume];

আমি কি কারণ জানতে পারি?
ব্যবহারকারী 558

-1
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    Static NSString *CellIdentifier = @"Cell";
    QTStaffViewCell *cell = (QTStaffViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    If (cell == nil)
    {

        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"QTStaffViewCell" owner:self options:nil];
        cell = [nib objectAtIndex: 0];

    }

    StaffData = [self.staffArray objectAtIndex:indexPath.row];
    NSString *title = StaffData.title;
    NSString *fName = StaffData.firstname;
    NSString *lName = StaffData.lastname;

    UIFont *FedSanDemi = [UIFont fontWithName:@"Aller" size:18];
    cell.drName.text = [NSString stringWithFormat:@"%@ %@ %@", title,fName,lName];
    [cell.drName setFont:FedSanDemi];

    UIFont *aller = [UIFont fontWithName:@"Aller" size:14];
    cell.drJob.text = StaffData.job;
    [cell.drJob setFont:aller];

    if ([StaffData.title isEqualToString:@"Dr"])
    {
        cell.drJob.frame = CGRectMake(83, 26, 227, 40);
    }
    else
    {
        cell.drJob.frame = CGRectMake(90, 26, 227, 40);

    }

    if ([StaffData.staffPhoto isKindOfClass:[NSString class]])
    {
        NSURL *url = [NSURL URLWithString:StaffData.staffPhoto];
        NSURLSession *session = [NSURLSession sharedSession];
        NSURLSessionDownloadTask *task = [session downloadTaskWithURL:url
                completionHandler:^(NSURL *location,NSURLResponse *response, NSError *error) {

      NSData *imageData = [NSData dataWithContentsOfURL:location];
      UIImage *image = [UIImage imageWithData:imageData];

      dispatch_sync(dispatch_get_main_queue(),
             ^{
                    cell.imageView.image = image;
              });
    }];
        [task resume];
    }
       return cell;}

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