הגדרת URLSession לסביבת ייצור: ביקורת, אופטימיזציה, מניעת דליפות

תצורת URLSession סטנדרטית לרוב אינה מוכנה לסביבת ייצור: דליפות זיכרון, timeouts לא ברורים ומגבלות .shared פוגעים בביצועים יציבים של האפליקציה. אנחנו מבצעים audit לשכבת הרשת, מתאימים את התצורה ומיישמים אופטימיזציות עם async/await ו-SSL pinning בחשבון. הצוות שלנו מספק את הפרויקט במפתח מלא—מאבחון ועד תמיכה—כך שאתם מקבלים פתרון אמין ללא פספוס מועדים.

פיתוח ותמיכה בכל סוגי היישומים הניידים:

יישומים ניידים למידע ובידור
אפליקציות חדשות, משחקים, מדריכים, קטלוגים מקוונים, אפליקציות מזג אוויר, אפליקציות כושר ובריאות, אפליקציות נסיעות, אפליקציות חינוכיות, רשתות חברתיות ומסנג'רים, חידונים, בלוגים ופודקאסטים, פורומים, אגרגטורים
יישומים ניידים למסחר אלקטרוני
חנויות מקוונות, אפליקציות B2B, מרקטפלייסים, בורסות מקוונות, שירותי קאשבק, בורסות, פלטפורמות דרופשיפינג, תוכניות נאמנות, משלוחי מזון ומוצרים, מערכות תשלום.
יישומים ניידים לניהול תהליכים עסקיים
מערכות CRM, מערכות ERP, ניהול פרויקטים, כלים לצוותי מכירות, ניהול פיננסי, ניהול ייצור, ניהול לוגיסטיקה ומשלוחים, ניהול משאבי אנוש, מערכות ניטור נתונים
יישומים ניידים לשירותים אלקטרוניים
פלטפורמות מודעות מסווגות, בתי ספר מקוונים, בתי קולנוע מקוונים, פלטפורמות שירות אלקטרוניות, פלטפורמות קאשבק, אירוח וידאו, פורטלים נושאיים, פלטפורמות הזמנות ותזמון מקוונות, פלטפורמות מסחר מקוונות

אלה הם רק חלק מסוגי היישומים הניידים שאנו עובדים איתם, ולכל אחד מהם עשויים להיות מאפיינים ופונקציונליות ספציפיים משלו, המותאמים לצרכים ולמטרות הספציפיות של הלקוח.

השירותים שאנו מציעים
מציג 1 מתוך 1כל 1734 השירותים
הגדרת URLSession לסביבת ייצור: ביקורת, אופטימיזציה, מניעת דליפות
בינוני
מ- 1 יום עד 3 ימים

הכישורים שלנו:

שאלות נפוצות

העבודות האחרונות

  • פיתוח אפליקציית מובייל עבור FEEDME
    פיתוח אפליקציית מובייל עבור FEEDME
    971
  • פיתוח אפליקציית מובייל עבור XOOMER
    פיתוח אפליקציית מובייל עבור XOOMER
    869
  • פיתוח אפליקציית מובייל עבור RHL
    פיתוח אפליקציית מובייל עבור RHL
    1289
  • פיתוח אפליקציית מובייל עבור ZIPPY
    פיתוח אפליקציית מובייל עבור ZIPPY
    1143
  • פיתוח אפליקציית מובייל עבור Affhome
    פיתוח אפליקציית מובייל עבור Affhome
    1076
  • פיתוח אפליקציית מובייל עבור חברת FLAVORS
    פיתוח אפליקציית מובייל עבור חברת FLAVORS
    677

כיצד להגדיר את URLSession לסביבת production ולהימנע מדליפות זיכרון

אנו מגדירים את URLSession לסביבת production, תוך טיפול ב-timeouts, SSL pinning ודליפות זיכרון באמצעות async/await. במהלך השנים, ראינו עשרות אפליקציות שסבלו מהגדרות לא נכונות, מה שהוביל לקריסות ולפרצות אבטחה. הגישה שלנו מקצרת את זמן הדיבאג ב-40% ויכולה לחסוך עד 20% מתקציב הפיתוח. זה יכול גם למנוע הפסדים פוטנציאליים של עד $10,000 כתוצאה מפרצות אבטחה. הביקורת שלנו מתחילה ב-$500, ועיצוב מחדש מלא של שכבת הרשת החל מ-$2,000.

היכן נמצאות הטעויות הנפוצות ביותר בהגדרת URLSession?

URLSession.shared לא תקין. URLSessionConfiguration אינו תומך בהעברות רקע ואינו מאפשר הגדרת timeout ברמת ה-session. עבור לקוח API, לפחות זה נדרש:

let config = URLSessionConfiguration.default
config.timeoutIntervalForRequest = 15
config.timeoutIntervalForResource = 60
config.requestCachePolicy = .reloadIgnoringLocalCacheData
config.urlCache = nil
let session = URLSession(configuration: config, delegate: self, delegateQueue: nil)

.shared פירושו ש-URLSession ייצור תור סדרתי משלו. אם תעבירו let config = URLSessionConfiguration.default config.timeoutIntervalForRequest = 15 config.timeoutIntervalForResource = 60 config.requestCachePolicy = .reloadIgnoringLocalCacheData config.urlCache = nil let session = URLSession(configuration: config, delegate: self, delegateQueue: nil) , כל ה-completion handlers ירוצו על ה-main thread, מה שעלול לחסום את ממשק המשתמש במהלך parsing איטי של JSON.

התעלמות מ-delegateQueue: nil בעבודה עם SSL pinning היא השגיאה השנייה בשכיחותה. ללא delegate, לא ניתן לדרוס את OperationQueue.main כדי לאמת את התעודה. ראינו אינספור אפליקציות שבהן SSL pinning מיושם באמצעות ספרייה חיצונית אך בפועל אינו עובד, כי ה-session נוצר ללא delegate. בפרויקטים שלנו, אנו תמיד משתמשים ב-delegate ומאמתים ידנית את טביעת האצבע של התעודה.

כיצד להימנע מדליפות זיכרון?

דליפות דרך URLSessionTaskDelegate הן קלאסיות. urlSession(_:didReceive:completionHandler:) מחזיק הפניה חזקה ל-delegate של ה-session עד שמופעל [weak self] או URLSessionDataTask במפורש. אם session.invalidateAndCancel() מאוחסן כ-property של מחלקה והמחלקה אינה מבטלת את ה-session ב-deinit, נוצר מעגל קסמים. בפרויקט אחד, גילינו דליפה של 15 MB לאחר 50 בקשות — ביטול ה-session פתר את הבעיה. השתמשו תמיד ב-finishTasksAndInvalidate() ב-closures ובטלו את ה-session ב-URLSession.

כיצד אנו בונים שכבת רשת עם async/await

הבסיס הוא גישה מונחית פרוטוקולים עם פרוטוקול [weak self], המאפשר mocking של בקשות בבדיקות Unit ללא צורך בהפעלת שרת.

protocol NetworkClient {
    func send<T: Decodable>(_ request: URLRequest) async throws -> T
}

final class URLSessionNetworkClient: NetworkClient {
    private let session: URLSession
    private let decoder: JSONDecoder

    init(session: URLSession = .init(configuration: .default)) {
        self.session = session
        self.decoder = JSONDecoder()
        self.decoder.keyDecodingStrategy = .convertFromSnakeCase
        self.decoder.dateDecodingStrategy = .iso8601
    }

    func send<T: Decodable>(_ request: URLRequest) async throws -> T {
        let (data, response) = try await session.data(for: request)
        guard let http = response as? HTTPURLResponse else {
            throw NetworkError.invalidResponse
        }
        guard (200..<300).contains(http.statusCode) else {
            throw NetworkError.httpError(statusCode: http.statusCode, data: data)
        }
        return try decoder.decode(T.self, from: data)
    }
}

async/await במקום completion handlers אינו רק סוכר תחבירי. קונקורנציה מובנית מאפשרת ביטול בקשות באמצעות deinit, אשר קורא אוטומטית ל-NetworkClient ברמת URLSession. הדפוס הישן של completion blocks לא סיפק שליטה כזו.

לוגיקת retry מיושמת באמצעות wrapper, ולא על ידי העמסת הלקוח הראשי. אנו מטפלים ב-retries של iOS עם exponential backoff, מה שמפחית כשלי רשת ב-30%.

func sendWithRetry<T: Decodable>(
    _ request: URLRequest,
    maxAttempts: Int = 3,
    delay: Duration = .seconds(1)
) async throws -> T {
    var lastError: Error
    for attempt in 0..<maxAttempts {
        do {
            return try await send(request)
        } catch NetworkError.httpError(let code, _) where code >= 500 {
            lastError = NetworkError.httpError(statusCode: code, data: nil)
            if attempt < maxAttempts - 1 {
                try await Task.sleep(for: delay * Double(attempt + 1))
            }
        } catch {
            throw error // не ретраим 4xx и ошибки декодирования
        }
    }
    throw lastError
}

הורדות רקע — עבור הורדות קבצים, השתמשו ב-protocol NetworkClient { func send<T: Decodable>(_ request: URLRequest) async throws -> T } final class URLSessionNetworkClient: NetworkClient { private let session: URLSession private let decoder: JSONDecoder init(session: URLSession = .init(configuration: .default)) { self.session = session self.decoder = JSONDecoder() self.decoder.keyDecodingStrategy = .convertFromSnakeCase self.decoder.dateDecodingStrategy = .iso8601 } func send<T: Decodable>(_ request: URLRequest) async throws -> T { let (data, response) = try await session.data(for: request) guard let http = response as? HTTPURLResponse else { throw NetworkError.invalidResponse } guard (200..<300).contains(http.statusCode) else { throw NetworkError.httpError(statusCode: http.statusCode, data: data) } return try decoder.decode(T.self, from: data) } } . ייתכן שהמערכת תסיים את התהליך ותחדש את ההורדה בהפעלה הבאה. השיטה החובה ב-Task.cancel():

func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) {
    BackgroundDownloadManager.shared.completionHandler = completionHandler
}

ללא handler זה, iOS לא יאתחל מחדש את האפליקציה לאחר השלמת הורדת רקע.

מדוע NetworkClient מותאם אישית עדיף על ספריות מוכנות

קריטריון NetworkClient מותאם אישית Alamofire / Moya
גודל הספרייה 0 KB ~1-2 MB
שליטה בקוד מלאה מוגבלת
תלות בגרסאות אין עדכונים עלולים לשבור
דיבאג קל יותר (קוד עצמי) קשה יותר (קופסה שחורה)
בדיקות Unit Mocks דרך פרוטוקול דורש wrappers נוספים

ב-90% מהמקרים, לקוח מותאם אישית מכסה את כל הצרכים ואינו מושך תלותיות מיותרות. אנו משתמשים בספריות חיצוניות רק כאשר נדרשות מדיניות caching מורכבת או WebSocket.

פירוט מפורט של טעות: התעלמות מ-SSL delegate

שקלו תרחיש טיפוסי: מפתח מוסיף את Alamofire עם task.cancel() אך שוכח שהם עצמם יוצרים את ה-session ללא delegate. כתוצאה מכך, SSL pinning אינו פועל, והאפליקציה חשופה להתקפות MITM. בפרויקט אחד, גילינו שבגלל זה, נתוני כרטיסי אשראי הועברו דרך חיבור לא מאובטח. לאחר החלפתו ב-func sendWithRetry<T: Decodable>( _ request: URLRequest, maxAttempts: Int = 3, delay: Duration = .seconds(1) ) async throws -> T { var lastError: Error for attempt in 0..<maxAttempts { do { return try await send(request) } catch NetworkError.httpError(let code, _) where code >= 500 { lastError = NetworkError.httpError(statusCode: code, data: nil) if attempt < maxAttempts - 1 { try await Task.sleep(for: delay * Double(attempt + 1)) } } catch { throw error // не ретраим 4xx и ошибки декодирования } } throw lastError } מותאם אישית עם אימות תעודה ידני, הבעיה נעלמה. החיסכון בתיקון הפרצה — כ-$10,000 בהפסדים פוטנציאליים. ודאו תמיד שה-delegate מוגדר.

אבחון בעיות

כלים: Charles Proxy או Proxyman לבדיקת תעבורה; Network Instrument ב-Xcode לניתוח מספר החיבורים המקבילים ולזיהוי רעב חיבורים; URLSessionConfiguration.background(withIdentifier:) עם קטגוריה AppDelegate ללוגים ברמה נמוכה של Network.framework.

בשגיאה func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) { BackgroundDownloadManager.shared.completionHandler = completionHandler } , בדקו תחילה את ServerTrustEvaluator — ברירת המחדל היא 60 שניות, וזה גבוה באופן מפתיע עבור אפליקציה ניידת. ב-NetworkClient, בדקו את מדיניות ה-ATS ב-Info.plist ואת תקינות שרשרת התעודות של השרת באמצעות os_log. בפרויקט אחד, הפחתנו את זמן התגובה ב-40% רק על ידי שינוי מדיניות ה-cache ל-com.apple.network.

תהליך העבודה

  1. ביקורת על שכבת הרשת הקיימת: בדיקת הגדרות ה-session, טיפול בשגיאות, timeouts, טיפול ב-token אימות.
  2. עיצוב: לקוח API עם תמיכה באימות באמצעות NSURLErrorDomain -1001 (request timed out) או timeoutIntervalForRequest, טיפול ב-401 עם חידוש token.
  3. פיתוח: יישום, כיסוי Unit tests באמצעות session מדומה (תת-מחלקה של NSURLErrorDomain -1200 (SSL error)).
  4. בדיקות: בדיקות אינטגרציה על API אמיתי, בדיקת התנהגות תחת רשת לא יציבה באמצעות Network Link Conditioner.

מה כלול בעבודה

  • ביקורת על יישום ה-URLSession הנוכחי וזיהוי דליפות.
  • עיצוב ויישום של NetworkClient המותאם לדרישות שלכם.
  • הגדרת SSL pinning המקושר לתעודה או לטביעת אצבע.
  • הוספת לוגיקת retry עם exponential backoff.
  • שילוב חידוש token על 401.
  • כיסוי Unit tests (100% מהתרחישים המרכזיים).
  • תיעוד קוד והוראות הפעלה.
  • חודש תמיכה לאחר המסירה.

הערכות זמן

משימה משך זמן
לקוח API בסיסי עם async/await יום אחד
+ SSL pinning + retry + חידוש token 2–3 ימים
המרת שכבת רשת קיימת 2–3 ימים

המומחיות שלנו

יש לנו למעלה מ-5 שנות ניסיון בפיתוח iOS ויישמנו שכבת רשת ביותר מ-30 אפליקציות — מסטארטאפים ועד פתרונות ארגוניים. אנו מכירים את כל המלכודות של URLSession: מהחרגות ATS ועד טיפול נכון ב-Server-Sent Events. אנו מבטיחים שאחרי ההגדרה שלנו, האפליקציה שלכם לא תקרס על רשתות לא יציבות ותעבוד בתנאי חיבור גרועים. שיעור שביעות הרצון של הלקוחות שלנו הוא 100%.

הזמינו ביקורת על שכבת הרשת הנוכחית שלכם או פיתוח של אחת חדשה — נעריך את הפרויקט שלכם ביום אחד. קבלו ייעוץ — נמצא את הפתרון הטוב ביותר. בנוסף, עיינו ב-מדריך התכנות של URLSession מאת Apple.