|
| 1 | +--- |
| 2 | +title: "Regex on Main Thread" |
| 3 | +sidebar_order: 30 |
| 4 | +redirect_from: |
| 5 | + - /product/issues/performance-issues/regex-decoding-main-thread/ |
| 6 | +description: "Learn more about Regex on Main Thread issues and how to diagnose and fix them." |
| 7 | +--- |
| 8 | + |
| 9 | +The main (or UI) thread in a mobile app is responsible for handling all user interaction and needs to be able to respond to gestures and taps in real time. If a long-running operation blocks the main thread, the app becomes unresponsive, impacting the quality of the user experience. |
| 10 | + |
| 11 | +Evaluating matches between strings and regular expressions (regex) can be long-running operations that may impact app responsiveness. If a long-running regex operation is detected on the main thread that can be offloaded to the background, Sentry will flag it as an issue. |
| 12 | + |
| 13 | +## Detection Criteria |
| 14 | + |
| 15 | +[Profiling](/product/profiling/) needs to be enabled for Sentry to detect Regex on Main Thread issues. Sentry looks for functions related to regular expressions that have been running on the main thread for at least 40ms. This threshold was chosen so that the function appears in a sufficient number of samples collected by the profile (~10ms per sample x 4 = ~40ms total) before it gets detected as an issue. |
| 16 | + |
| 17 | +## Function Evidence |
| 18 | + |
| 19 | +To find additional information about your Regex on Main Thread problem, go to its **Issue Details** page and scroll down to the "Function Evidence" section, which shows the following: |
| 20 | + |
| 21 | +- **Transaction Name:** The name of the transaction where the issue was detected. |
| 22 | +- **Suspect function:** The function that triggered the issue detection (in this case, a regular expression function). |
| 23 | +- **Duration:** How long the function took to execute and the number of consecutive samples collected by the profiler that contained the function |
| 24 | + |
| 25 | + |
| 26 | + |
| 27 | +To view the entire profile associated with the issue, click the “View Profile” button. |
| 28 | + |
| 29 | +The profile will indicate where the suspect function was called from, along with other functions being called _by_ the suspect function: |
| 30 | + |
| 31 | + |
| 32 | + |
| 33 | +## Stack Trace |
| 34 | + |
| 35 | +The “Stack Trace” section shows a full stack trace for where the detected regex function was called from: |
| 36 | + |
| 37 | + |
| 38 | + |
| 39 | +## Example |
| 40 | + |
| 41 | +### iOS |
| 42 | + |
| 43 | +The following code searches for matches against a regular expression in a large string: |
| 44 | + |
| 45 | +```swift |
| 46 | +let url = Bundle.main.url(forResource: "mobydick", withExtension: "txt")! |
| 47 | +let text = try! String(contentsOf: url) |
| 48 | +let regex = try! NSRegularExpression(pattern: #"([tT]he)?.*([wW]hale)"#, options: [.dotMatchesLineSeparators]) |
| 49 | +let results = regex.matches(in: text, range: NSMakeRange(0, text.count)) |
| 50 | +``` |
| 51 | + |
| 52 | +Performance could be improved by moving the calls both to create and use the regex to a lower priority queue (as well as the calls to load the text field being searched, in this example): |
| 53 | + |
| 54 | +```swift |
| 55 | +DispatchQueue.global(qos: .userInitiated).async { |
| 56 | + let url = Bundle.main.url(forResource: "mobydick", withExtension: "txt")! |
| 57 | + let text = try! String(contentsOf: url) |
| 58 | + let regex = try! NSRegularExpression(pattern: #"([tT]he)?.*([wW]hale)"#, options: [.dotMatchesLineSeparators]) |
| 59 | + let results = regex.matches(in: text, range: NSMakeRange(0, text.count)) |
| 60 | + DispatchQueue.main.async { |
| 61 | + // display results... |
| 62 | + } |
| 63 | +} |
| 64 | +``` |
0 commit comments