Objective-C转Swift:UnsafeMutableRawPointer指针偏移赋值报错求助
Let's break down what's going wrong here and fix it step by step.
The Core Problem
In your Objective-C code, pixels is a UInt32 * pointer—when you do pixels + i * width + j, the pointer advances by (i*width +j) elements of UInt32 (each 4 bytes). But in your Swift code, you're using UnsafeMutableRawPointer, which treats advanced(by:) as a byte offset. So your current code is shifting the pointer by way too few bytes (1 byte per step instead of 4), leading to corrupted memory and invalid pixel data.
The Fix
Instead of working with raw pointers directly, bind your allocated memory to a UInt32 typed pointer. This matches the behavior of your Objective-C code and makes pointer operations safe and intuitive.
Here's the corrected Swift code:
// First, make sure your RGBMake function returns UInt32 (matches OC's RGBAMake) func RGBMake(r: Int, g: Int, b: Int, a: Int) -> UInt32 { return UInt32(a) << 24 | UInt32(b) << 16 | UInt32(g) << 8 | UInt32(r) } func imageWithGrayArray(_ orArr: [[Int]]) -> UIImage { let width = 512 let height = 512 let bytesPerPixel = 4 let bytesPerRow = bytesPerPixel * width let bitsPerComponent = 8 // Allocate memory and bind to UInt32 pointer (matches OC's UInt32* pixels) let pixelCount = width * height let pixelBytes = pixelCount * MemoryLayout<UInt32>.stride guard let pixels = malloc(pixelBytes)?.bindMemory(to: UInt32.self, capacity: pixelCount) else { fatalError("Failed to allocate pixel memory") } memset(pixels, 0, pixelBytes) for i in 0 ..< orArr.count { let subArray = orArr[i] for j in 0 ..< subArray.count { // Now we can access pixels like a typed array, just like OC let grayValue = subArray[j] pixels[i * width + j] = RGBMake(r: grayValue, g: grayValue, b: grayValue, a: 255) } } let colorSpace = CGColorSpaceCreateDeviceRGB() guard let context = CGContext( data: pixels, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: CGImageAlphaInfo.last.rawValue | CGImageByteOrderInfo.order32Big.rawValue ) else { free(pixels) fatalError("Failed to create bitmap context") } guard let cgImage = context.makeImage() else { free(pixels) fatalError("Failed to create CGImage") } let image = UIImage(cgImage: cgImage) free(pixels) return image }
Key Changes Explained
- Typed Pointer Binding:
bindMemory(to: UInt32.self, capacity: pixelCount)converts the raw pointer to aUnsafeMutablePointer<UInt32>. Now, when you dopixels[index], it automatically accesses the correct 4-byte UInt32 element—exactly like your Objective-C code. - Correct Offset Calculation:
i * width + jworks as a direct index into the typed pointer, no manual byte math needed. - Proper Type for RGB Value: The
RGBMakefunction returnsUInt32, matching the type expected by the pixel buffer (and OC'sRGBAMake). - Safety Improvements: Added guard clauses to handle memory allocation/context creation failures, and ensured we always free the allocated memory even if something goes wrong.
- Consistent Bytes Per Row: Used
widthinstead of hardcoding 512 forbytesPerRowto keep the code maintainable.
Why Your Original Swift Code Failed
advanced(by: i * width + j)onUnsafeMutableRawPointermoves the pointer byi*width +jbytes, not elements. Since each pixel is 4 bytes, you needed to multiply byMemoryLayout<UInt32>.stride(which is 4) to get the correct offset.storeBytes(of: ..., as: Int.self)was writing anInt(8 bytes on 64-bit systems) into a 4-byte UInt32 slot, causing memory overwrites and corruption.
内容的提问来源于stack exchange,提问作者user9865359

