আপনি কীভাবে একটি বিলম্বের পরে একটি ব্লককে ট্রিগার করবেন, যেমন-পারফর্মসাইলেক্টর: উইজ অবজেক্ট: আফটার ডেলি:?


735

কোনও বিলম্বের পরেও কোনও আধ্যাত্মিক প্যারামিটারের সাথে কোনও ব্লককে কল করার কোনও উপায় আছে যেমন ব্যবহার করার performSelector:withObject:afterDelay:মতো int/ double/ float?


এটি একটি বিরল পয়েন্ট যেখানে জিসিডি কিছু করতে পারে এনএসওরেশন তাই না?
বেনামে হোয়াইট

উত্তর:


1174

আমি আপনি যা খুঁজছেন মনে dispatch_after()। কোনও প্যারামিটার গ্রহণ করার জন্য এটির জন্য আপনার ব্লক প্রয়োজন, তবে আপনি কেবলমাত্র ব্লকটিকে স্থানীয় স্থান থেকে এই পরিবর্তনগুলি ক্যাপচার করতে দিতে পারেন।

int parameter1 = 12;
float parameter2 = 144.1;

// Delay execution of my block for 10 seconds.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
    NSLog(@"parameter1: %d parameter2: %f", parameter1, parameter2);
});

আরও: https://developer.apple.com/docamentation/dispatch/1452876-dispatch_ after


88
আসলে, এটা সত্য নয়। কোনও ব্লকের ক্যাপচার করা অবজেক্টস যা __ ব্লক স্টোরেজ হিসাবে চিহ্নিত নয় এবং ব্লকটি ধরে রেখেছে, এবং এটি ধ্বংস হয়ে যাওয়ার পরে ব্লকটি ছেড়ে দেওয়া হবে (যখন এটির সংরক্ষণের সংখ্যা 0 হয়)। এখানে তার সাথে ডকুমেন্টেশন এখানে রয়েছে: developer.apple.com/library/mac/docamentation/Cocoa/Conceptual/…
রায়ান

9
এই dispatch_time(DISPATCH_TIME_NOW, 10ull * NSEC_PER_SEC)স্নিপেট কদর্য এর জন্য কি কোনও পরিষ্কার উপায় নেই?
সামওয়ারমেট

7
হ্যাঁ, dispatch_get_current_queue()সর্বদা যে সারিটি কোডটি চালানো হচ্ছে তা ফিরিয়ে দেয়। সুতরাং যখন এই কোডটি মূল থ্রেড থেকে চালানো হবে, তখন ব্লকটি মূল থ্রেডেও কার্যকর করা হবে।
রায়ান

20
dispatch_get_current_queue()এখন
হ্রাস

9
NSEC_PER_SEC ছাড়াও, NSEC_PER_MSEC এরও অস্তিত্ব রয়েছে, আপনি যদি মিলিসেকেন্ডগুলি নির্দিষ্ট করতে চান;)
সিপ্রক্র্যাক

504

আপনি dispatch_afterপরে কোনও ব্লক কল করতে ব্যবহার করতে পারেন । এক্সকোডে, টাইপিং শুরু করুন dispatch_afterএবং নীচে Enterস্বতঃপূরণে হিট করুন :

এখানে চিত্র বর্ণনা লিখুন

দুটি যুক্তি হিসাবে "আর্গুমেন্ট" হিসাবে এখানে একটি উদাহরণ। আপনাকে কোনও ধরণের ম্যাক্রোর উপর নির্ভর করতে হবে না এবং কোডটির উদ্দেশ্যটি স্পষ্ট:

সুইফট 3, সুইফট 4

let time1 = 8.23
let time2 = 3.42

// Delay 2 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
    print("Sum of times: \(time1 + time2)")
}

সুইফট 2

let time1 = 8.23
let time2 = 3.42

// Delay 2 seconds
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2.0 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) { () -> Void in
        println("Sum of times: \(time1 + time2)")
}

উদ্দেশ্য গ

CGFloat time1 = 3.49;
CGFloat time2 = 8.13;

// Delay 2 seconds
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    CGFloat newTime = time1 + time2;
    NSLog(@"New time: %f", newTime);
});

45
বিলম্বের সময়টি দ্বিগুণ না হওয়ার বিষয়ে সতর্ক থাকুন। সুতরাং NSEC_PER_SEC * 0.5 আধা সেকেন্ডের জন্য চেষ্টা করে দেখুন এটি কার্যকর হবে না! আপনাকে মিলি সেকেন্ডে নেমে NSEC_PER_MSEC * 500 ব্যবহার করতে হবে So সুতরাং আপনাকে নিজের কোডের নমুনাটি পরিবর্তন করতে হবে: লোকাল এনএসইসি_PER_SEC এর ভগ্নাংশ ব্যবহার করতে পারবেন না তা দেখানোর জন্য ইনসেকেন্ডস = 2।
মালহাল

11
@মালহাল আসলে, NSEC_PER_SEC * 0.5একই হিসাবে কাজ করবে NSEC_PER_MSEC * 500। আপনি যদি মনে রাখবেন যে ঠিক dispatch_timea৪-বিট পূর্ণসংখ্যার প্রত্যাশা করে, তবে এটির মানটি ন্যানোসেকেন্ডে রয়েছে। NSEC_PER_SECহিসাবে সংজ্ঞায়িত করা হয় 1000000000ullএবং ভাসমান-পয়েন্ট ধ্রুবক দিয়ে গুণ 0.5করলে 500000000.0স্পষ্টভাবে একটি 64-বিট পূর্ণসংখ্যায় ফিরে কাস্ট করার পূর্বে ফলনকারী পয়েন্ট গণিত সম্পাদন করে would সুতরাং এর একটি ভগ্নাংশটি ব্যবহার করা পুরোপুরি গ্রহণযোগ্য NSEC_PER_SEC
জুনজি

202

এক্সকোড অন্তর্নির্মিত কোড স্নিপেট লাইব্রেরি ব্যবহার সম্পর্কে কীভাবে?

এখানে চিত্র বর্ণনা লিখুন

সুইফটের জন্য আপডেট:

অনেকগুলি ভোট আমাকে এই উত্তরটি আপডেট করতে অনুপ্রাণিত করেছিল।

বিল্ট-ইন এক্সকোড কোড স্নিপেট লাইব্রেরিতে dispatch_afterকেবলমাত্র objective-cভাষার জন্য রয়েছে। লোকেরা এর জন্য নিজস্ব কাস্টম কোড স্নিপেটও তৈরি করতে পারে Swift

এটি এক্সকোডে লিখুন।

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(<#delayInSeconds#> * Double(NSEC_PER_SEC))), dispatch_get_main_queue(), {
        <#code to be executed after a specified delay#>
    })

এই কোডটি টানুন এবং কোড স্নিপেট লাইব্রেরি এরিয়ায় ফেলে দিন। এখানে চিত্র বর্ণনা লিখুন

কোড স্নিপেট তালিকার নীচে, একটি নতুন সত্ত্বা থাকবে My Code Snippet। একটি শিরোনাম জন্য এটি সম্পাদনা করুন। পরামর্শের জন্য আপনি টাইপ করার সাথে সাথে Xcode পূরণ করুন Completion Shortcut

আরও তথ্যের জন্য ক্রিয়েটিং কাস্টমকোডসনিপেট দেখুন

সুইফট 3 আপডেট করুন

এই কোডটি টানুন এবং কোড স্নিপেট লাইব্রেরি এরিয়ায় ফেলে দিন।

DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(<#delayInSeconds#>)) {
    <#code to be executed after a specified delay#>
}

19
এক্সকোডে আসলেই কি কেউ এই বৈশিষ্ট্যটি ব্যবহার করে? আমি এটিকে কোড পরামর্শ পপআপ হিসাবে টাইপ করতে পছন্দ করি এবং ব্যবহার করার মতোই সহজ।
সুপারট্যাকনোবফ

6
যতক্ষণ না আমি জানতাম কেবল কপি এবং পেস্ট করা কোডের সহজতম উপায়। এখন আমি কেবল টেনে এনে
ফেলেছি

58

জাইমে চমের উত্তরের উপর প্রসারিত করে আমি নীচের মতো একটি এনএসবজেক্ট + ব্লক বিভাগ তৈরি করেছি। আমি অনুভব করেছি যে এই পদ্ধতিগুলি বিদ্যমান performSelector:এনএসবজেক্টের পদ্ধতির সাথে আরও ভালভাবে মেলে

NSObject + + Blocks.h

#import <Foundation/Foundation.h>

@interface NSObject (Blocks)

- (void)performBlock:(void (^)())block afterDelay:(NSTimeInterval)delay;

@end

NSObject + + Blocks.m

#import "NSObject+Blocks.h"

@implementation NSObject (Blocks)

- (void)performBlock:(void (^)())block
{
    block();
}

- (void)performBlock:(void (^)())block afterDelay:(NSTimeInterval)delay
{
    void (^block_)() = [block copy]; // autorelease this if you're not using ARC
    [self performSelector:@selector(performBlock:) withObject:block_ afterDelay:delay];
}

@end

এবং এর মতো ব্যবহার করুন:

[anyObject performBlock:^{
    [anotherObject doYourThings:stuff];
} afterDelay:0.15];

5
delayহওয়া উচিত NSTimeInterval(যা একটি হল double)। #import <UIKit/UIKit.h>প্রয়োজন হয় না। এবং, আমি দেখতে পাচ্ছি না কেন কার্যকর - (void)performBlock:(void (^)())block;হতে পারে, তাই শিরোলেখ থেকে সরানো যেতে পারে।
অর্থ-বিষয়গুলি

@ অর্থ-বিষয়গুলি, উভয় বৈধ পয়েন্ট +1, আমি সেই অনুযায়ী আমার উত্তর আপডেট করেছি।
অলিভার পিয়ারমাইন

এটি মোটেও সঠিক নয়, পারফরম্যান্স নির্বাচনকারীকে ডেলোকের উপর স্পষ্টভাবে সরিয়ে ফেলতে হবে, না হলে আপনি সত্যিই অদ্ভুত আচরণ এবং ক্র্যাশগুলিতে চলে যাবেন, প্রেরণ_পরটি ব্যবহার করা আরও সঠিক
প্রেরণ_পরে পিটার লাপিসু

21

কোথাও কোথাও ক্লাসে (যেমন "ইউটিল"), বা অবজেক্টের কোনও বিভাগে: সম্ভবত জিসিডির মাধ্যমে সহজতর:

+ (void)runBlock:(void (^)())block
{
    block();
}
+ (void)runAfterDelay:(CGFloat)delay block:(void (^)())block 
{
    void (^block_)() = [[block copy] autorelease];
    [self performSelector:@selector(runBlock:) withObject:block_ afterDelay:delay];
}

সুতরাং ব্যবহার করতে:

[Util runAfterDelay:2 block:^{
    NSLog(@"two seconds later!");
}];

3
@ জাইমি চ্যাম আপনি কী ভাবেন যে জিসিডি দিয়ে যাওয়া কঠিন?
বেসি

2
জিসিডি দিয়ে যাওয়ার পারফর্মসিলেক্টরের তুলনায় কিছুটা আলাদা আচরণ আছে: ডিলে: পরে, তাই জিসিডি ব্যবহার না করার কারণ থাকতে পারে। দেখ, উদাহরণস্বরূপ, নিম্নলিখিত প্রশ্ন: stackoverflow.com/questions/10440412/...
fishinear

আপনি ব্লকটি সম্পাদনকারীতে পাস করার আগে কেন এটি অনুলিপি করেন?
সি রোলে

1
দেরি করার জন্য দুঃখিত. @ ক্রোয়াড: আমি মনে করি স্ট্যাক থেকে গাদা হয়ে ব্লকটি সরানোর জন্য আপনার অনুলিপিটি দরকার।
জাইমে চ্যাম

@ বেসি: আরও শব্দযুক্ত এবং উদ্দেশ্যটি আড়াল করে।
জাইমে চ্যাম

21

সুইফটের জন্য আমি dispatch_afterপদ্ধতিটি ব্যবহার করে একটি গ্লোবাল ফাংশন তৈরি করেছি, বিশেষ কিছু নয় । এটি পাঠযোগ্য এবং সহজেই ব্যবহারযোগ্য বলে এটিকে আমি আরও পছন্দ করি:

func performBlock(block:() -> Void, afterDelay delay:NSTimeInterval){
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC))), dispatch_get_main_queue(), block)
}

যা আপনি নিম্নলিখিত হিসাবে ব্যবহার করতে পারেন:

performBlock({ () -> Void in
    // Perform actions
}, afterDelay: 0.3)

1
আমি যুক্তিগুলি অদলবদল করে এর নাম পরিবর্তন করার পরামর্শ দিই after। তারপরে আপনি লিখতে পারেন:after(2.0){ print("do somthing") }
লার্স ব্লামবার্গ

16

এখানে আমার 2 সেন্ট = 5 পদ্ধতি রয়েছে;)

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

void dispatch_after_delay(float delayInSeconds, dispatch_queue_t queue, dispatch_block_t block) {
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
    dispatch_after(popTime, queue, block);
}

void dispatch_after_delay_on_main_queue(float delayInSeconds, dispatch_block_t block) {
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_after_delay(delayInSeconds, queue, block);
}

void dispatch_async_on_high_priority_queue(dispatch_block_t block) {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), block);
}

void dispatch_async_on_background_queue(dispatch_block_t block) {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), block);
}

void dispatch_async_on_main_queue(dispatch_block_t block) {
    dispatch_async(dispatch_get_main_queue(), block);
}

8

পারফর্মসিলিেক্টর: উইওবজেক্ট সর্বদা একটি অবজেক্ট নেয়, যাতে ইন / ডাবল / ফ্লোট ইত্যাদি যুক্তিগুলি পাস করার জন্য ..... আপনি এর মতো কিছু ব্যবহার করতে পারেন।

// এনএস নাম্বার একটি অবজেক্ট ..

[self performSelector:@selector(setUserAlphaNumber:)
     withObject: [NSNumber numberWithFloat: 1.0f]       
     afterDelay:1.5];



-(void) setUserAlphaNumber: (NSNumber*) number{

     [txtUsername setAlpha: [number floatValue] ];

}

একইভাবে আপনি [এনএসএন নাম্বারবিহীন আইটেম:] ইত্যাদি ব্যবহার করতে পারেন .... এবং প্রাপ্ত পদ্ধতিতে আপনি নম্বরটি [বিন্যাস] বা [সংখ্যা দ্বিগুণ] হিসাবে আপনার বিন্যাসে রূপান্তর করতে পারেন।


8

প্রেরণ_পরিবর্তন ফাংশন একটি নির্দিষ্ট সময়ের পরে একটি প্রেরণ সারিতে একটি ব্লক অবজেক্ট প্রেরণ করে। ২.০ সেকেন্ডের পরে কিছু UI সম্পর্কিত ট্যাক্স সম্পাদন করতে নীচের কোডটি ব্যবহার করুন।

            let delay = 2.0
            let delayInNanoSeconds = dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC)))
            let mainQueue = dispatch_get_main_queue()

            dispatch_after(delayInNanoSeconds, mainQueue, {

                print("Some UI related task after delay")
            })

দ্রুত 3.0:

            let dispatchTime: DispatchTime = DispatchTime.now() + Double(Int64(2.0 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)
            DispatchQueue.main.asyncAfter(deadline: dispatchTime, execute: {

          })

একটি টাইপো রয়েছে: এর mainQueue, পরিবর্তেmainQueue)
বাস্তিয়ান

5

বিলম্বের পরে কাজ সারি করার জন্য সুইফট 3 উপায় এখানে।

DispatchQueue.main.asyncAfter(
  DispatchTime.now() + DispatchTimeInterval.seconds(2)) {
    // do work
}

5

বার বার বিরক্তিকর জিসিডি কল করা রোধ করার জন্য এক সহায়ক সহায়ক :

public func delay(bySeconds seconds: Double, dispatchLevel: DispatchLevel = .main, closure: @escaping () -> Void) {
    let dispatchTime = DispatchTime.now() + seconds
    dispatchLevel.dispatchQueue.asyncAfter(deadline: dispatchTime, execute: closure)
}

public enum DispatchLevel {
    case main, userInteractive, userInitiated, utility, background
    var dispatchQueue: DispatchQueue {
        switch self {
        case .main:                 return DispatchQueue.main
        case .userInteractive:      return DispatchQueue.global(qos: .userInteractive)
        case .userInitiated:        return DispatchQueue.global(qos: .userInitiated)
        case .utility:              return DispatchQueue.global(qos: .utility)
        case .background:           return DispatchQueue.global(qos: .background)
        }
    }
}

এখন আপনি কেবল মূল থ্রেডে নিজের কোডটি বিলম্ব করুন :

delay(bySeconds: 1.5) { 
    // delayed code
}

আপনি যদি নিজের কোডটি বিভিন্ন থ্রেডে বিলম্ব করতে চান :

delay(bySeconds: 1.5, dispatchLevel: .background) { 
    // delayed code that will run on background thread
}

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

import HandySwift    

delay(bySeconds: 1.5) { 
    // delayed code
}

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

ডিফল্টরূপে আমার পদ্ধতিটি মূল থ্রেড ব্যবহার করে যাতে এটি না ঘটে। প্রেরণযোগ্য লেভেল। ডিফল্ট দেখুন .মেন?
জিহুত


4

সুইফ্ট 3-তে, আমরা 'এন' সেকেন্ডের বিলম্বের পরে কোনও ক্রিয়া বা ক্রিয়া ট্রিগার করতে কেবল DispatchQueue.main.asyncAfter ফাংশনটি ব্যবহার করতে পারি। এখানে কোডে আমরা 1 সেকেন্ড পরে বিলম্ব স্থির করেছি। আপনি এই ফাংশনটির শরীরে এমন কোনও ফাংশন কল করেছেন যা 1 সেকেন্ডের বিলম্বের পরে ট্রিগার করবে।

let when = DispatchTime.now() + 1
DispatchQueue.main.asyncAfter(deadline: when) {

    // Trigger the function/action after the delay of 1Sec

}

4

এক্সকোড 10.2 এবং সুইফট 5 এবং তারপরে

DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: {
   // code to execute                 
})

1

আপনি হয় নিজের ক্লাসে যুক্তি মোড়ানো করতে পারেন, বা পদ্ধতি কলটি এমন পদ্ধতিতে মোড়ানো করতে পারেন যা আদিম ধরণের পাস করার প্রয়োজন হয় না। তারপরে আপনার বিলম্বের পরে সেই পদ্ধতিটি কল করুন এবং সেই পদ্ধতির মধ্যে আপনি যে নির্বাচকটি সম্পাদন করতে চান তা সম্পাদন করুন।


1

সুইফটে বিলম্বের পরে আপনি কীভাবে একটি ব্লক ট্রিগার করতে পারেন তা এখানে:

runThisAfterDelay(seconds: 2) { () -> () in
    print("Prints this 2 seconds later in main queue")
}

/// EZSwiftExtensions
func runThisAfterDelay(seconds seconds: Double, after: () -> ()) {
    let time = dispatch_time(DISPATCH_TIME_NOW, Int64(seconds * Double(NSEC_PER_SEC)))
    dispatch_after(time, dispatch_get_main_queue(), after)
}

এটি আমার রেপোতে একটি স্ট্যান্ডার্ড ফাংশন হিসাবে অন্তর্ভুক্ত ।


1

সুইফট 3 এবং এক্সকোড 8.3.2

এই কোডটি আপনাকে সহায়তা করবে, আমি একটি ব্যাখ্যাও যুক্ত করব

// Create custom class, this will make your life easier
class CustomDelay {

    static let cd = CustomDelay()

    // This is your custom delay function
    func runAfterDelay(_ delay:Double, closure:@escaping ()->()) {
        let when = DispatchTime.now() + delay
        DispatchQueue.main.asyncAfter(deadline: when, execute: closure)
    }
}


// here how to use it (Example 1)
class YourViewController: UIViewController {

    // example delay time 2 second
    let delayTime = 2.0

    override func viewDidLoad() {
        super.viewDidLoad()

        CustomDelay.cd.runAfterDelay(delayTime) {
            // This func will run after 2 second
            // Update your UI here, u don't need to worry to bring this to the main thread because your CustomDelay already make this to main thread automatically :)
            self.runFunc()
        }
    }

    // example function 1
    func runFunc() {
        // do your method 1 here
    }
}

// here how to use it (Example 2)
class YourSecondViewController: UIViewController {

    // let say you want to user run function shoot after 3 second they tap a button

    // Create a button (This is programatically, you can create with storyboard too)
    let shootButton: UIButton = {
        let button = UIButton(type: .system)
        button.frame = CGRect(x: 15, y: 15, width: 40, height: 40) // Customize where do you want to put your button inside your ui
        button.setTitle("Shoot", for: .normal)
        button.translatesAutoresizingMaskIntoConstraints = false
        return button
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        // create an action selector when user tap shoot button
        shootButton.addTarget(self, action: #selector(shoot), for: .touchUpInside)   
    }

    // example shoot function
    func shoot() {
        // example delay time 3 second then shoot
        let delayTime = 3.0

        // delay a shoot after 3 second
        CustomDelay.cd.runAfterDelay(delayTime) {
            // your shoot method here
            // Update your UI here, u don't need to worry to bring this to the main thread because your CustomDelay already make this to main thread automatically :)
        }
    }   
}

0

আমি বিশ্বাস করি যে লেখক কীভাবে একটি ভগ্নাংশের (দেরি) জন্য অপেক্ষা করবেন তা জিজ্ঞাসা করছেন না, পরিবর্তে নির্বাচকটির যুক্তি হিসাবে একটি স্কেলারটি কীভাবে পাস করবেন (ওজেক্ট :) সহ এবং আধুনিক উদ্দেশ্য সি এর দ্রুততম উপায়টি হ'ল:

[obj performSelector:...  withObject:@(0.123123123) afterDelay:10]

আপনার নির্বাচককে তার প্যারামিটারটি এনএসএনম্বারে পরিবর্তন করতে হবে এবং ফ্লোটভ্যালু বা ডাবলভ্যালুর মতো নির্বাচক ব্যবহার করে মানটি পুনরুদ্ধার করতে হবে

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