Why crash in swift 4.2, but in objective-c is ok?

First is code in swift and objective-c.
ModelContainer is simulate an object management data source


class ModelContainer: NSObject {
    
    var list: Array = Array<Int>.init()
    
    
    func setCall() { self.list = [1,2,3] }
    func getCall() -> Array<Int> { return self.list }
}

@interface ModelContainer : NSObject

@property (copy, nonatomic) NSArray *list;

- (void)setCall;
- (NSArray*)getCall;

@end

@implementation ModelContainer

- (instancetype)init {
    if (self = [super init]) { _list = [NSArray new]; }
    return self;
}

- (void)setCall { self.list = [NSArray arrayWithObjects:@"222",@"333", nil]; }
- (NSArray*)getCall { return self.list; }

@end

In the business code, the multi-threaded call is as follows.

self.container is ModelContainer

DispatchQueue.global().async { while true { self.container.setCall() } }
DispatchQueue.global().async { while true { print(self.container.getCall()) } }
dispatch_async(dispatch_get_global_queue(0, 0), ^{
    while (1) {
        [self.container setCall];
    }
});

dispatch_async(dispatch_get_global_queue(0, 0), ^{
    while (1) {
        NSLog(@"%@", [self.container getCall]);
    }
});

but in swift will crash with EXC_BREAKPOINT, but objective-c is ok.
Below is a screenshot:

Because your code is relying on ill-defined behavior in ObjC and running into safety checks in Swift.

You’re racing on one thread to read a variable another is writing. ObjC has C semantics, and (correct me if I’m wrong) reading and writing concurrently is essentially behavior left to the implementation. On x86 Macs and most other Apple platforms, it’s left to the processor and memory to figure out what happens here — I’m not sure that read and write are guaranteed to be atomic, or whether the writes to set up the contents of the array and those to set up the variable are guaranteed to be visible in any kind of specific order to the reading thread, so you may or may not crash. The program isn’t just incorrect, it’s incorrect silently.

My assumption here is that you’re running into enforcement of the Law of Exclusivity which is one of the principles of Swift; no two pieces of code may access the same thing if either is attempting to write to it. I don’t know if that’s the case since you didn’t include any error messages from the console. But at least the Swift safety net shows you that your code is incorrect loudly.

This is not how you write correct concurrent code; you probably want to make writes mutually exclusive, or use other concurrency techniques that ensure memory for that specific array isn’t read and written at the same time.

1 Like

why should found this
this is another code in objective-c .
if i have a conversation list, and will update or insert in different place.
usually we will use lock or dispatch queue with serial to protect crash.but i found another code to do this like the way above

@interface ViewController ()
@property (copy, nonatomic) NSArray *list;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        while (1) {
            self.list = [[NSArray alloc] initWithObjects:@1, @2, @3, nil];
        }
    });

    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        while (1) {
            NSLog(@"%@", self.list);
        }
    });
}

this code is crash with EXC_BREAKPOINT too. by in Objc. if i use a model container to holding object, it won't crash again. so i try it in swift.


maybe you are right, is because Objc and swift 's different.
Objc has c semantics and it's silently.


so could you tell me what happen in Objc to protect crash? tks


by the way, in Objc, i think is nonatomic

Concurrency is too vast a topic to touch in a single blog post, unfortunately. There is a lot of literature on the topic, and as far as the tools Apple offers, you can find many WWDC talks on the subject as well as documentation for the tools in Dispatch and guided introductions to it as well.

2 Likes

tks you help.
maybe i need to found something to explain why use a model container is ok.
and different between this two way..