2

I have a method that is in charge of loading details about events (queries a sqlite database for titles, descriptions, thumbnail paths, etc.) that, since I need to call this for a large amount of events, I am dispatching to a background thread using Grand Central Dispatch.

The problem is I am getting a UIKit thread exception (letting me know I'm running UI methods on a thread other than the main thread, causing the app to crash). I'm not changing the UI at all so this was nearly impossible to find, but I finally narrowed it down to one line of code:

bool retina = (UIScreen.MainScreen.Scale > 1.0);

I am using UIScreen to determine if the device has a retina screen (to determine if the thumbnail image path should have "@2x" appended at the end) and just accessing this (what appears to be a static variable) throws that UIKit exception.

Is there a work-around for determining if the screen is retina that doesn't use UIKit (or is background-thread safe), or is there a better way to figure this out?

Note: I'm using Xamarin (C#) to create the app, but any answer in swift is perfectly fine and easy to convert.

Chris Schlitt
  • 561
  • 1
  • 4
  • 20
  • 1
    Couldn't you just set the variable once on startup (i.e. main thread) and use it thereafter? – Phillip Mills Jul 28 '17 at 18:20
  • I thought of that, but the method is called in so many different places that it would require a lot of refactoring. Unless I setup a singleton that determined that on startup, but would that be overkill just to determine if the screen was retina? Or is that a good idea? – Chris Schlitt Jul 28 '17 at 18:25
  • Re: "different places" Do you have a specific object type for managing the data loading? Is it initialized on the main thread? (Otherwise, I don't know the Xamarin architecture but in a "Xcode" app, I'd be tempted to make it a property of the application delegate -- not perfect but reasonable for a single variable.) – Phillip Mills Jul 28 '17 at 18:32

1 Answers1

3

First, you don't have to specify @2 when opening images you just display on screen. iOS selects the correct version with UIImage(named: "BaseName").

But if you need to is here your Swift code:

func isRetina() -> Bool
{
    var scale: CGFloat = 0.0
    DispatchQueue.main.sync
    {
        scale = UIScreen.main.scale
    }

    return scale > 1.0
}

Because you use it in many place, consider putting this in some utility/base class.

meaning-matters
  • 21,929
  • 10
  • 82
  • 142