Swift对接PHP+MySQL注册报错:无法转换闭包类型问题咨询
Hey there! Let's break down how to fix that type mismatch error and get your Swift registration flow connected to your PHP+MySQL backend properly.
1. Why the Type Conversion Error Happens
That error pops up because you're using an older Objective-C-style completion handler signature with Swift's modern URLSession API. In Swift 3 and later:
NSDatawas replaced with Swift's nativeDatatypeNSErrorwas swapped for Swift's built-inErrorprotocol- The closure signature changed from
(NSData?, URLResponse?, NSError?) -> ()to(Data?, URLResponse?, Error?) -> Void
You should also switch from legacy NSURL/NSMutableURLRequest classes to Swift's native URL and URLRequest for better compatibility.
2. Fixed Swift Registration Code
Here's an updated version of your signUp action, with proper type handling, safe parameter encoding, and user-friendly error checking:
@IBAction func signUp(_ sender: Any) { // Step 1: Validate text field inputs guard let fullName = name.text?.trimmingCharacters(in: .whitespacesAndNewlines), !fullName.isEmpty, let email = emailTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines), !email.isEmpty, let password = passwordTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines), password.count >= 6 else { // Show validation error to user let alert = UIAlertController(title: "Oops", message: "Please fill all fields correctly (password needs at least 6 characters)", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .default)) present(alert, animated: true) return } // Step 2: Prepare the network request guard let url = URL(string: "http://localhost:8888/helo/register.php") else { print("Invalid backend URL") return } var request = URLRequest(url: url) request.httpMethod = "POST" request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") // Encode parameters safely to avoid issues with special characters let parameters: [String: String] = [ "Fullname": fullName.lowercased(), "Email": email, "Password": password ] let parameterString = parameters.compactMap { key, value in guard let encodedValue = value.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else { return nil } return "\(key)=\(encodedValue)" }.joined(separator: "&") request.httpBody = parameterString.data(using: .utf8) // Step 3: Send request with correct closure signature let task = URLSession.shared.dataTask(with: request) { data, response, error in // Switch back to main thread to update UI DispatchQueue.main.async { if let error = error { print("Network error: \(error.localizedDescription)") let alert = UIAlertController(title: "Error", message: "Failed to connect to server. Please try again.", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .default)) self.present(alert, animated: true) return } // Validate HTTP response status code guard let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) else { print("Invalid server response") let alert = UIAlertController(title: "Error", message: "Server returned an error. Please try again.", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .default)) self.present(alert, animated: true) return } // Parse JSON response from backend guard let data = data else { print("No data received from server") return } do { if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] { if let success = json["success"] as? Bool, success { // Registration successful let alert = UIAlertController(title: "Success", message: "Account created!", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { _ in // Navigate to login screen or home here })) self.present(alert, animated: true) } else { let errorMessage = json["message"] as? String ?? "Registration failed" let alert = UIAlertController(title: "Error", message: errorMessage, preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .default)) self.present(alert, animated: true) } } } catch { print("JSON parsing error: \(error.localizedDescription)") } } } task.resume() }
3. Corresponding PHP Backend (register.php)
Here's a secure, production-ready example of your register.php that connects to MySQL, validates input, and returns structured JSON responses:
<?php header('Content-Type: application/json'); // Database configuration (update these values to match your setup) $host = 'localhost'; $dbname = 'your_database_name'; $username = 'your_db_username'; $password = 'your_db_password'; try { // Connect to MySQL using PDO (more secure and flexible than mysqli) $pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8", $username, $password); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // Retrieve POST parameters $fullName = $_POST['Fullname'] ?? ''; $email = $_POST['Email'] ?? ''; $password = $_POST['Password'] ?? ''; // Validate input if (empty($fullName) || empty($email) || empty($password) || strlen($password) < 6) { echo json_encode([ 'success' => false, 'message' => 'Please fill all fields correctly (password needs at least 6 characters)' ]); exit; } // Check if email is already registered $stmt = $pdo->prepare("SELECT id FROM users WHERE email = :email"); $stmt->bindParam(':email', $email); $stmt->execute(); if ($stmt->rowCount() > 0) { echo json_encode([ 'success' => false, 'message' => 'Email is already registered' ]); exit; } // Hash password (NEVER store plain-text passwords!) $hashedPassword = password_hash($password, PASSWORD_DEFAULT); // Insert new user into database $stmt = $pdo->prepare("INSERT INTO users (full_name, email, password) VALUES (:fullName, :email, :password)"); $stmt->bindParam(':fullName', $fullName); $stmt->bindParam(':email', $email); $stmt->bindParam(':password', $hashedPassword); if ($stmt->execute()) { echo json_encode([ 'success' => true, 'message' => 'Registration successful' ]); } else { echo json_encode([ 'success' => false, 'message' => 'Failed to create account' ]); } } catch(PDOException $e) { echo json_encode([ 'success' => false, 'message' => 'Server error: ' . $e->getMessage() ]); } ?>
4. Critical Things to Remember
- Network Permissions: Since you're using HTTP for localhost, add this to your
Info.plistto bypass Apple's App Transport Security (use HTTPS for production!):<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> </dict> - Password Security: Always use
password_hash()for storage andpassword_verify()for login validation—never store plain-text passwords. - Error Handling: The Swift code includes basic error handling, but you can expand it to validate email formats or add loading states for better UX.
- Parameter Encoding: Using
addingPercentEncodingensures special characters (like spaces or @) don't break your request.
内容的提问来源于stack exchange,提问作者Sam Banana

